C++ 线程采用引用参数编译失败
C++ Thread taking reference argument failed compile
#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
应该只通过 value 复制参数并传递存储在线程中的一些对象以绑定函数的引用参数f1
.
我觉得如果我能理解这个result_of
在做什么以及为什么会出错,我就能更好地理解原因。那么有人可以引导我完成错误消息吗?特别是std::_Bind_simple<void (*(double))(double&)>
和std::result_of<void (*(double))(double&)>
的含义。
编辑:我知道如果我传递一个值,线程只会在副本上工作并且在线程returns之后没有效果。那不是我关心的。我想知道为什么它现在给出错误,但它没有给 SO 上的其他帖子出错,如下所示:Difference between pointer and reference as thread parameter
I know if I pass a value, the thread will only work on the copy and has no effect after the thread returns.
不,那是不正确的。代码不应该默默地复制并在副本上工作,标准规定它甚至不能编译。
标准要求复制被调用函数的参数(到 C++ 运行时管理的存储中),然后将副本作为右值转发。因此,在您的示例中,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&)
。
That is not my concern. I want to know why it is giving error now, but it was not giving error to other posts on SO
这些帖子使用的是旧的 C++11 之前的编译器或不符合 C++11 标准要求的不合格编译器,并且错误地编译了代码。
Jonathan 的回答是肯定的。花在学习上的时间是值得的。
与此同时,修改代码将执行您想要的操作 - 即向线程函数发送引用:
thread t1(f1, std::ref(ret));
#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
应该只通过 value 复制参数并传递存储在线程中的一些对象以绑定函数的引用参数f1
.
我觉得如果我能理解这个result_of
在做什么以及为什么会出错,我就能更好地理解原因。那么有人可以引导我完成错误消息吗?特别是std::_Bind_simple<void (*(double))(double&)>
和std::result_of<void (*(double))(double&)>
的含义。
编辑:我知道如果我传递一个值,线程只会在副本上工作并且在线程returns之后没有效果。那不是我关心的。我想知道为什么它现在给出错误,但它没有给 SO 上的其他帖子出错,如下所示:Difference between pointer and reference as thread parameter
I know if I pass a value, the thread will only work on the copy and has no effect after the thread returns.
不,那是不正确的。代码不应该默默地复制并在副本上工作,标准规定它甚至不能编译。
标准要求复制被调用函数的参数(到 C++ 运行时管理的存储中),然后将副本作为右值转发。因此,在您的示例中,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&)
。
That is not my concern. I want to know why it is giving error now, but it was not giving error to other posts on SO
这些帖子使用的是旧的 C++11 之前的编译器或不符合 C++11 标准要求的不合格编译器,并且错误地编译了代码。
Jonathan 的回答是肯定的。花在学习上的时间是值得的。
与此同时,修改代码将执行您想要的操作 - 即向线程函数发送引用:
thread t1(f1, std::ref(ret));