问题描述
我试图理解 std::thread
的构造函数,但无法理解如何表示/处理参数类型。从 cppreference 来看,一个简化的构造函数可以勾画如下:
class thread {
public:
template <class Function,class Arg>
thread(Function&& f,Arg&& arg) {
// something happening
std::invoke(decay_copy(std::forward<Function>(f)),decay_copy(std::forward<Arg>(arg)));
// something else happening
}
};
cppreference 将 decay_copy
定义为:
template <class T>
std::decay_t<T> decay_copy(T&& v) { return std::forward<T>(v); }
我用以下示例进行了一些实验:
struct X{};
int main() {
X x1{};
X& x2 = x1;
auto f = []() { return; };
thread t1{f,x1}; // arg should be of type X& after the inner std::forward<Arg>(arg);
thread t2{f,x2}; // arg should be of type X& after the inner std::forward<Arg>(arg);
thread t3{f,X{}}; // arg should be of type X&& after the inner std::forward<Arg>(arg);
}
根据我的分析,x1
和 x2
都是内部 std::forward
之后的左值引用类型,而X{}
是右值引用类型。我相信我们需要以某种方式将 x1
和 x2
分开以按值或按引用传递它。分析将我引向三个问题:
- 以上分析是否正确?
-
decay_copy
如何正确解开类型? - 开始一段时间后,我想知道:哦,打扰了,为什么会如此牵扯?可以更容易吗?答案当然是否定的,但我对整个操作仍然缺乏直觉。
感谢您的任何提示、建议或解释!
解决方法
标准线程复制(或移动)到参数类型的衰减版本中。衰减后的版本既不是引用也不是 const 也不是 volatile 也不是数组(数组和函数变成了指针)。
如果您需要左值引用参数,请使用引用包装器。否则线程构造函数中被调用的函数将获得一个右值;衰减复制仅确定您在线程函数中传递的右值是如何从 std 线程参数构造的。