Переслать вариационный аргумент в поток с лямбдой
У меня проблемы с поиском, как использовать std::thread()
с лямбдами. А именно, при наличии аргумента с переменным значением лямбда получает аргументы путем пересылки. В качестве примера:
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: компилирует
A.2: компилирует
B.1: компилирует
B.2: не компилируется
Я не понимаю
- Почему
std::thread()
(2) версия с использованием (B) не компилируется и (A.2) делает? - Почему существуют различия между (B.1) и (B.2)
2 ответа
Попробуй с
template<typename... T>
auto foo(T&&... t){
[](T&&... u){ }(std::forward<T>(t)...); // (1)
return std::thread( // (2)
[](auto &&... u){ },
std::forward<T>(t)...
);
}
Я имею в виду: в лямбде вы переходите к std::thread()
, auto && ...
вместо T && ...
, Или, может быть, T const & ...
,
Я не являюсь языковым слоем, и, возможно, кто-то может исправить меня, но мне кажется, что существует конфликт между универсальными ссылками и ссылками на r-значения. И тот факт, что std::thread()
передать копии следующих аргументов первому.
Когда ты пишешь
template<typename... T>
auto foo(T&&... t)
&&
универсальные ссылки и T...
становиться int
когда вы звоните foo(1)
, а также int &
когда вы звоните foo(n)
,
Внутри функции вы получаете
[](int){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int){ },
std::forward<int>(t)...
);
в случае f(0)
,
И это работает, потому что оба лямбда ждут int
по копии, и это всегда работает.
Но когда вы звоните f(n)
внутри foo()
ты получаешь
[](int &){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int &){ },
std::forward<int>(t)...
);
и это работает для первого звонка, потому что лямбда подождите int
переменная левой ссылки (int &
) и получить int
переменная левой ссылки, но не работает для второго вызова, потому что std::thread
передать копию std::forward<int>(t)
(так что правильная ссылка, int &&
) к лямбде, которая ждет левой ссылки.
std::thread
не может просто пересылать свои аргументы в лямбду по ссылке, потому что это будет означать, что два потока потенциально имеют одновременный доступ к аргументам без синхронизации. Так что вместо этого std::thread
создает временные копии аргументов и передает их в лямбду. Потому что они временные, они ценности. Это работает в A.2, потому что лямбда-параметр является rvalue ссылкой (потому что T
является int
, так T&&
является int&&
). Это не работает в B.2, потому что параметр лямбды является ссылкой lvalue (потому что T
является int&
, так T&&
является int&
). Как говорит max66, вы, вероятно, хотите использовать auto&&...
в вашей лямбде, чтобы она могла принять все, что ей передано.