C ++线程参考参数失败编译

时间:2016-03-31 19:10:11

标签: c++ c++11 stdthread result-of

#include<iostream>
#include<thread>
using namespace std;

void f1(double& ret) {
   ret=5.;
}

int main() {
   double ret=0.;
   thread t1(f1, ret);
   t1.join();
   cout << "ret=" << ret << endl;
}

以上代码无法使用以下error message进行编译:

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
In file included from /usr/local/include/c++/5.3.0/thread:39:0,
                 from main.cpp:2:
/usr/local/include/c++/5.3.0/functional: In instantiation of 'struct std::_Bind_simple<void (*(double))(double&)>':
/usr/local/include/c++/5.3.0/thread:137:59:   required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(double&); _Args = {double&}]'
main.cpp:11:21:   required from here
/usr/local/include/c++/5.3.0/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>'
       typedef typename result_of<_Callable(_Args...)>::type result_type;
                                                             ^
/usr/local/include/c++/5.3.0/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>'
         _M_invoke(_Index_tuple<_Indices...>)
         ^

我知道我可以使用std::ref()来传递参数。但是如果我通过值传递,为什么它是一个错误,因为thread应该只通过复制参数并传递一些存储在线程内的对象与函数{{1的引用参数绑定}}

我觉得如果我能理解这个f1正在做什么以及它为什么会出错,我可以更好地理解其中的原因。所以有人可以引导我完成错误消息吗?特别是result_ofstd::_Bind_simple<void (*(double))(double&)>的含义。

编辑:我知道如果我传递一个值,该线程将只对副本起作用,并在线程返回后无效。这不是我关心的问题。我想知道它为什么现在给出错误,但它并没有给SO上的其他帖子提供错误,如下所示:Difference between pointer and reference as thread parameter

2 个答案:

答案 0 :(得分:13)

  

我知道如果我传递一个值,该线程将只对副本起作用,并且在线程返回后没有效果。

不,那不对。代码不应该默默地复制并处理副本,标准说它甚至不能编译。

该标准要求将被调用函数的参数复制(由C ++运行时管理的存储),然后将副本转发为rvalues 。因此,在您的示例f1中,传递了double类型的右值,类型double&的参数无法绑定到该右值。

标准要求的原因是没有静默复制和数据丢失:如果函数需要可修改的引用,那么除非使用reference_wrapper显式传递引用,否则它将无法编译。

您得到的编译器错误涉及result_of,因为这是我如何使用GCC std::thread检查是否可以使用提供的参数调用该函数。我使用result_of<decltype(&f1)(double)>来检查是否可以使用类型为&f1的右值调用函数指针void(*)(double&)(类型为double})。它不能使用该类型的参数调用,因此未定义嵌套类型result_of<decltype(&f1)(double)>::type,因此编译器说:

error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>'

错误有点令人困惑,因为C ++声明符规则意味着decltype(&f1)(double)显示为void(*(double))(double&)

  

这不是我关心的问题。我想知道它为什么现在给出错误,但它没有给SO上的其他帖子错误

这些帖子使用的是旧的C ++ 11或不符合标准的编译器,这些编译器不符合C ++ 11标准的要求并错误地编译了代码。

答案 1 :(得分:2)

Jonathan的回答是肯定的。花在研究它上面的时间很长。

与此同时,修改代码将会做你想要的 - 即将参考发送到线程函数:

thread t1(f1, std::ref(ret));