[cfe-dev] thread(F&&) fails when F is not MoveAssignable
Howard Hinnant
hhinnant at apple.com
Sun Dec 16 14:55:34 PST 2012
On Dec 16, 2012, at 5:22 PM, Gordon Henriksen <gordonhenriksen at me.com> wrote:
> [Sorry for the cross-post, but cfe-users doesn't seem to be active yet.]
>
> The snippet at the end of this message fails to compile with clang-libc++.
>
> Is LaunchByMove() invalid C++11, or is this a libc++ bug?
>
> I have a body of code written using the failing LaunchByMove pattern. I guess
> I'll have to work around the issue, perhaps with the LaunchByCopy pattern.
> Enforcing that style may prove error-prone, though.
>
> The relevant section in N3242 is this:
>
> 30.3.1.2 thread constructors
> …
>
> template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
>
> Given a function as follows:
>
> template <class T> typename decay<T>::type decay_copy(T&& v)
> { return std::forward<T>(v); }
>
> Requires: F and each Ti in Args shall satisfy the MoveConstructible
> requirements. INVOKE(decay_copy(std::forward<F>(f)),
> decay_copy(std::forward<Args>(args))...) (20.8.2) shall be a valid
> expression.
>
> There doesn't appear to be any Swappable or MoveAssignable requirement for
> template argument F, at least in the draft.
>
> — Gordon
>
>
> cat <<'EOT' >test.cpp
> #include <thread>
> class CopyableNotAssignable {
> int &n_;
> public:
> CopyableNotAssignable(int &n) : n_(n) { }
> };
> void LaunchByMove() {
> int n;
> std::thread(CopyableNotAssignable(n)).join(); // expect-error
> }
> void LaunchByCopy() {
> int n;
> CopyableNotAssignable cna(n);
> std::thread(cna).join(); // successful
> }
> EOT
> xcrun clang -std=c++0x -stdlib=libc++ -c test.cpp
>
>
> Output:
> In file included from test.cpp:1:
> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/thread:330:5: error:
> attempt to use a deleted function
> __invoke(_VSTD::move(_VSTD::get<0>(__t)), ...
> ^
> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/thread:340:5: note:
> in instantiation of function template specialization
> 'std::__1::__threaad_execute<CopyableNotAssignable, , >' requested here
> __threaad_execute(*__p, _Index());
> ^
> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/thread:352:41: note:
> in instantiation of function template specialization
> 'std::__1::__thread_proxy<std::__1::tuple<CopyableNotAssignable> >'
> requested here
> int __ec = pthread_create(&__t_, 0, &__thread_proxy<_Gp>, __p.get());
> ^
> test.cpp:9:3: note: in instantiation of function template specialization
> 'std::__1::thread::thread<CopyableNotAssignable, , void>' requested here
> std::thread(CopyableNotAssignable(n)).join();
> ^
> /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/type_traits:825:5: note:
> function has been explicitly marked deleted here
> ~__nat() = delete;
> ^
> 1 error generated.
CopyableNotAssignable does not appear to be a callable object with zero parameters. LaunchByMove and LaunchByCopy should both fail. Or technically, they exhibit undefined behavior, so anything could happen. A compile-time error is the highest quality solution.
Howard
More information about the cfe-dev
mailing list