#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_of
和std::_Bind_simple<void (*(double))(double&)>
的含义。
编辑:我知道如果我传递一个值,该线程将只对副本起作用,并在线程返回后无效。这不是我关心的问题。我想知道它为什么现在给出错误,但它并没有给SO上的其他帖子提供错误,如下所示:Difference between pointer and reference as thread parameter
答案 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));