[cfe-dev] thread(F&&) fails when F is not MoveAssignable

Howard Hinnant hhinnant at apple.com
Sun Dec 16 15:36:42 PST 2012


On Dec 16, 2012, at 6:27 PM, Gordon Henriksen <gordonhenriksen at me.com> wrote:

> On 2012-12-16, at 14:55, Howard Hinnant wrote:
> 
>> 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?
>>> 
>>> 
>>> 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
>> 
>> 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
> 
> Thanks, Howard; that is an error in my reduction. The true test is this, and using 'bool *flag_;' instead of 'bool &flag_;' does make this case compile for reasons which are mysterious to me.
> 
> namespace {
> 	class SimpleJoinThread {
> 		bool &flag_;
> 	public:
> 		SimpleJoinThread(bool &flag) : flag_(flag) { }
> 		void operator()() { flag_ = true; }
> 	};
> } // End anonymous namespace.
> 
> TEST(ThreadTests, SimpleJoin) {
> 	bool flag = false;
> 	std::thread(SimpleJoinThread(flag)).join();
> 	EXPECT_TRUE(flag);
> }
> 
> There's something more complex going on in the compilation unit, though; the reduced case I presented does compile on its own with the addition of void operator()() {}.

Is this a correct translation of the test?

#include <thread>
#include <iostream>
#include <cassert>

namespace {
    class SimpleJoinThread {
        bool &flag_;
    public:
        SimpleJoinThread(bool &flag) : flag_(flag) { }
        void operator()() { flag_ = true; }
    };
} // End anonymous namespace.

int main()
{
    bool flag = false;
    std::thread(SimpleJoinThread(flag)).join();
    assert(flag);
}

The above is compiling and running for me (without assert).  If it isn't for you, then perhaps we're looking at a libc++ or clang++ bug that has been recently fixed.  But first let's zero in on a precise copy/pasteable test.

I ran this test with both:

clang++ -std=c++11 -stdlib=libc++ test.cpp

and

clang++ -std=c++03 -stdlib=libc++ test.cpp

Howard




More information about the cfe-dev mailing list