c++ - std::thread 使用带有 ref arg 的 lambda 编译失败

标签 c++ generics lambda c++14

我正在阅读 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/

相关文章:

c++ - DbgHelp.dll 是 Windows 内置的吗?我可以相信它在那里吗?

java - 如何调用不带参数的泛型方法?

java - 为什么我不能声明一个参数化的静态类变量?

c# - 使用 lambda 从嵌套列表中分离值

lambda - F# 不带参数的 lambda 表达式

c++ - 为什么我的 vector<int> 不默认为 0?

c++ - NEON中的_mm_hadd_ps等于多少?

c# - 泛型类型参数与参数实例的类型不同

c# - 如何查询 C# 字典并返回一组特定的值

c# - 将 C++ map 数据传递给 C#