[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