I'm having trouble finding how use std::thread()
with lambdas. Namely, with having a variadic argument lambda receive the arguments by forwarding. As an example:
template<typename... T>
auto foo(T&&... t){
[](T&&... t){}(std::forward<T>(t)...); // (1)
return std::thread( // (2)
[](T&&... t){},
std::forward<T>(t)...
);
}
auto bar(){
int n=1;
foo(1); (A)
foo(n); (B)
}
A.1: compiles
A.2: compiles
B.1: compiles
B.2: doesn't compile
I don't understand:
std::thread()
(2) version using (B) doesn't compile and (A.2) does?Try with
template<typename... T>
auto foo(T&&... t){
[](T&&... u){ }(std::forward<T>(t)...); // (1)
return std::thread( // (2)
[](auto &&... u){ },
std::forward<T>(t)...
);
}
I mean: in the lambda you pass to std::thread()
, auto && ...
instead of T && ...
. Or, maybe, T const & ...
.
I'm not a language layer, and maybe someone can correct me, but it seems to me that there is a clash between universal references and r-value references. And the fact that std::thread()
pass copies of the following arguments to the first one.
When you write
template<typename... T>
auto foo(T&&... t)
the &&
are universal-references and T...
become int
, when you call foo(1)
, and int &
, when you call foo(n)
.
Inside the function you get
[](int){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int){ },
std::forward<int>(t)...
);
in case f(0)
.
And this works because both lambda are waiting a int
by copy and this ever works.
But when you call f(n)
, inside foo()
you get
[](int &){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int &){ },
std::forward<int>(t)...
);
and this works for the first call, because the lambda wait a int
left-reference variable (int &
) and get a int
left-reference variable, but doesn't works for the second call because std::thread
pass a copy of std::forward<int>(t)
(so a right-reference, int &&
) to the lambda that wait for a left-reference.