我正在阅读 C++ concurrency in action .第 2.4 章介绍了一种 parallell_accumulate 算法。
我尝试(作为学习实验)用通用 lambda 替换那里使用的仿函数。
我将编译错误归结为:
#include <thread>
template <typename T>
struct f {
void operator() (T& result) { result = 1;}
};
int main() {
int x = 0;
auto g = [](auto& result) { result = 1; };
std::thread(f<int>(), std::ref(x)); // COMPILES
std::thread(g, std::ref(x)); // FAILS TO COMPILE
}
错误信息:
In file included from /usr/include/c++/4.9/thread:39:0,
from foo.cpp:1:
/usr/include/c++/4.9/functional: In instantiation of ‘struct std::_Bind_simple<main()::<lambda(auto:1&)>(std::reference_wrapper<int>)>’:
/usr/include/c++/4.9/thread:140:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = main()::<lambda(auto:1&)>&; _Args = {std::reference_wrapper<int>}]’
foo.cpp:13:31: required from here
/usr/include/c++/4.9/functional:1665:61: error: no type named ‘type’ in ‘class std::result_of<main()::<lambda(auto:1&)>(std::reference_wrapper<int>)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/usr/include/c++/4.9/functional:1695:9: error: no type named ‘type’ in ‘class std::result_of<main()::<lambda(auto:1&)>(std::reference_wrapper<int>)>’
_M_invoke(_Index_tuple<_Indices...>)
^
我的编译器版本
$ g++ --version
g++ (Ubuntu 4.9.1-16ubuntu6) 4.9.1
为什么 lambda 编译失败,而仿函数编译失败?
编辑:如何使用通用 lambda 实现仿函数正在执行的操作(分配给 ref)?
最佳答案
模板参数推导不查看转换的同一主题的另一个变体。
operator()
的 f<int>
是
void operator() (int& result);
当你通过 reference_wrapper<int>
对其,调用转换函数 (operator int &
),产生一个可以绑定(bind)到 result
的引用.
operator()
你的通用 lambda 是
template<class T> void operator() (T& result) const;
如果它通过了 reference_wrapper
左值,它会推导出 T
作为 reference_wrapper
然后无法编译分配。 (赋值给 reference_wrapper
会重置“引用”而不是影响值。)
但它甚至在此之前就失败了,因为标准要求您传递给 std::thread
的内容必须可以使用纯右值调用 - 并且非常量左值引用不会绑定(bind)到纯右值。这是您看到的错误 - result_of
不包含 type
因为您的仿函数不可用于参数类型。如果你试图做 g(std::ref(x));
, 铿锵 produces一个相当明显的错误:
main.cpp:16:5: error: no matching function for call to object of type '(lambda at main.cpp:11:14)'
g(std::ref(x));
^
main.cpp:11:14: note: candidate function [with $auto-0-0 = std::__1::reference_wrapper<int>] not viable: expects an l-value for 1st argument
auto g = [](auto& result) { result = 1; };
^
您可能应该考虑仅通过引用捕获相关的本地:
auto g = [&x]() { x = 1; };
或者,如果出于某种原因,您必须使用通用 lambda,那么您可以使用 reference_wrapper
按值(或通过 const 引用),然后使用 get()
解包:
auto g = [](auto result) { result.get() = 1; };
或者添加一个 std::bind
这将打开 reference_wrapper
s,它让模板参数推导做正确的事情(帽子提示@Casey):
std::thread(std::bind(g, std::ref(x)));
或者也许不用这个reference_wrapper
废话,写你的 lambda 来取一个非拥有的指针:
auto g = [](auto* result) { *result = 1; };
std::thread(g, &x);
关于c++ - std::thread 使用带有 ref arg 的 lambda 编译失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28154400/