使用 lambda 将可变参数转发给线程
Forward variadic argument to thread with lambda
我无法找到如何将 std::thread()
与 lambda 一起使用。即,具有可变参数的 lambda 通过转发接收参数。例如:
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) 之间存在差异
试试
template<typename... T>
auto foo(T&&... t){
[](T&&... u){ }(std::forward<T>(t)...); // (1)
return std::thread( // (2)
[](auto &&... u){ },
std::forward<T>(t)...
);
}
我的意思是:在 lambda 中,您传递给 std::thread()
、auto && ...
而不是 T && ...
。或者,也许 T const & ...
.
我不是语言层,也许有人可以纠正我,但在我看来,通用引用和右值引用之间存在冲突。并且 std::thread()
将以下参数的 副本 传递给第一个参数。
当你写
template<typename... T>
auto foo(T&&... t)
&&
是通用引用,当您调用 foo(1)
时 T...
变为 int
,而当您调用 [=24] 时 int &
=].
在你得到的函数里面
[](int){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int){ },
std::forward<int>(t)...
);
万一f(0)
.
这行得通,因为两个 lambda 都在等待 int
复制,这一直行得通。
但是当你调用 f(n)
时,在 foo()
中你会得到
[](int &){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int &){ },
std::forward<int>(t)...
);
这适用于第一次调用,因为 lambda 等待 int
左引用变量 (int &
) 并获得 int
左引用变量,但没有t 适用于第二次调用,因为 std::thread
将 std::forward<int>(t)
的 copy 传递给等待左参考。
std::thread
不能简单地将其参数通过引用转发给 lambda,因为这意味着两个线程可能在没有同步的情况下同时访问参数。因此,std::thread
创建参数的临时副本,并将其传递给 lambda。因为它们是临时的,所以它们是右值。这在 A.2 中有效,因为 lambda 的参数是右值引用(因为 T
是 int
,所以 T&&
是 int&&
)。它在 B.2 中不起作用,因为 lambda 的参数是左值引用(因为 T
是 int&
,所以 T&&
是 int&
)。就像 max66 所说的那样,您可能想在 lambda 中使用 auto&&...
以便它可以接受传递给它的任何内容。
我无法找到如何将 std::thread()
与 lambda 一起使用。即,具有可变参数的 lambda 通过转发接收参数。例如:
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) 之间存在差异
试试
template<typename... T>
auto foo(T&&... t){
[](T&&... u){ }(std::forward<T>(t)...); // (1)
return std::thread( // (2)
[](auto &&... u){ },
std::forward<T>(t)...
);
}
我的意思是:在 lambda 中,您传递给 std::thread()
、auto && ...
而不是 T && ...
。或者,也许 T const & ...
.
我不是语言层,也许有人可以纠正我,但在我看来,通用引用和右值引用之间存在冲突。并且 std::thread()
将以下参数的 副本 传递给第一个参数。
当你写
template<typename... T>
auto foo(T&&... t)
&&
是通用引用,当您调用 foo(1)
时 T...
变为 int
,而当您调用 [=24] 时 int &
=].
在你得到的函数里面
[](int){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int){ },
std::forward<int>(t)...
);
万一f(0)
.
这行得通,因为两个 lambda 都在等待 int
复制,这一直行得通。
但是当你调用 f(n)
时,在 foo()
中你会得到
[](int &){ }(std::forward<int>(t)); // (1)
return std::thread( // (2)
[](int &){ },
std::forward<int>(t)...
);
这适用于第一次调用,因为 lambda 等待 int
左引用变量 (int &
) 并获得 int
左引用变量,但没有t 适用于第二次调用,因为 std::thread
将 std::forward<int>(t)
的 copy 传递给等待左参考。
std::thread
不能简单地将其参数通过引用转发给 lambda,因为这意味着两个线程可能在没有同步的情况下同时访问参数。因此,std::thread
创建参数的临时副本,并将其传递给 lambda。因为它们是临时的,所以它们是右值。这在 A.2 中有效,因为 lambda 的参数是右值引用(因为 T
是 int
,所以 T&&
是 int&&
)。它在 B.2 中不起作用,因为 lambda 的参数是左值引用(因为 T
是 int&
,所以 T&&
是 int&
)。就像 max66 所说的那样,您可能想在 lambda 中使用 auto&&...
以便它可以接受传递给它的任何内容。