C++ 关于C++;std::thread中的自动类型转换行为
我创建了两个类C++ 关于C++;std::thread中的自动类型转换行为,c++,multithreading,c++11,rvalue-reference,C++,Multithreading,C++11,Rvalue Reference,我创建了两个类cl1和cl2,并且cl1有一个构造函数,它接受cl2&参数。 我有三个函数,一个以cl1为参数,一个以cl1&为参数,一个以cl1&为参数 #include <thread> #include <iostream> class cl1; class cl2; class cl2 { public: int y; cl2(int y) : y(y) {} //ctor }; class cl1 {
cl1
和cl2
,并且cl1
有一个构造函数,它接受cl2&
参数。
我有三个函数,一个以cl1
为参数,一个以cl1&
为参数,一个以cl1&
为参数
#include <thread>
#include <iostream>
class cl1;
class cl2;
class cl2 {
public:
int y;
cl2(int y) : y(y) {} //ctor
};
class cl1 {
public:
int x;
cl1(int x) : x(x) {} //ctor
cl1(cl2& ob1) : x(ob1.y * 2) {} //ctor for automatic conversion of cl2& to cl1, x = y*2
};
void do_work_with_cl(cl1 ob) { //This works as usual by actually copying the object through the conversion constructor
std::cout << "The x of ob is " << ob.x << std::endl;
}
void do_work_with_cl_rref(cl1&& ob) { //I guess this works because it takes an rvalue and the automatic
//conversion ctor of cl1 does just that
std::cout <<"Inside the function that takes cl1 as rvalue, x of ob is" << ob.x << std::endl;
}
void do_work_with_cl_lref(cl1& ob) { //This doesn't work as ob is non-const lvalue reference
std::cout << "lvalue referenced but the object created through implicit conversion is temporary(i.e rvalue)" << std::endl;
}
int main() {
//Normal non-threaded calls
cl2 ob(100); //create a cl2 object
do_work_with_cl(ob); //This is ok
do_work_with_cl_rref(ob); //This too works
//do_work_with_cl_lref(ob) //This fails, as suspected
std::cout << "Thread part" << std::endl
//Now calling the functions through a thread
std::thread t1(do_work_with_cl_rref, ob); //Thought this could work here, but doesn't
//The other functions also don't work, but I can understand why.
t1.join();
}
#包括
#包括
cl1类;
cl2类;
cl2类{
公众:
int-y;
cl2(int-y):y(y){}//
};
cl1类{
公众:
int x;
cl1(intx):x(x){}//
cl1(cl2&ob1):x(ob1.y*2){}//用于将cl2&自动转换为cl1的向量,x=y*2
};
void do_work_with_cl(cl1 ob){//这与通常一样,通过转换构造函数实际复制对象
STD::CUT< P>第30. 3.1.2/3的C++标准表示:
“Requires:F和Args中的每个Ti应满足可移动的构造要求。INVOKE(detacy\u COPY(std::forward(F))、detacy\u COPY(std::forward(Args))…)
(20.8.2)应为有效表达式”
表达式<代码>衰变副本(x)
在30.2.6中定义:
“在本条款的几个地方,使用了操作DECAY\u COPY(x)
。所有这些用法都意味着调用函数DECAY\u COPY(x)
,并使用结果,其中DECAY\u COPY
的定义如下:”
模板类型名称衰减::类型衰减\u副本(T&v)
{return std::forward(v);}
由于decay
操作会从对象中删除cv限定符,因此需要有一个通用有效的转换构造函数或从类型cl1
到类型cl2
的转换操作符。要检查这一点,std::thread
的转发机制显然会生成对c2
的实例。这将失败,因为右值引用无法绑定到转换构造函数中的非常量左值引用
如果您将构造函数的签名从
cl1(cl2&ob1)
更改为cl1(cl2 const&ob1)
它适用于GCC 4.7.2,因为右值引用可以绑定到左值引用到const
到底是什么问题?顺便说一句,上面的代码在vs2012更新1中构建得很好。@claptrap我得到错误的原因,以及我的评论中的推理是否有任何错误。前一个是主要原因不过,还是要估计一下。哦,谢谢你的通知,我还没有在vs2012上测试过,我正在使用linux。tl;dr:总是定义正确的转换构造函数,引用常量,然后向所有创建一个非常量引用的构造函数的人射击。如果你需要修改原始对象中的某些内容,那么你就做错了什么-或者你需要一些可变的
@Griwes:holy words,只是一个小小的更正:那不是一个复制构造函数,而是一个转换构造函数啊..明白了。非常感谢你的解释(以及幕后工作)!我想知道为什么ideone和vs2012的代码(如claptrap所说)不过可以吗?@Andariel:他们可能有不同的线程支持库实现,不执行右值引用的转换。我个人认为GCC的方法更符合标准,但我可能错了
In file included from /usr/include/c++/4.7/ratio:38:0,
from /usr/include/c++/4.7/chrono:38,
from /usr/include/c++/4.7/thread:38,
from main.cpp:1:
/usr/include/c++/4.7/type_traits: In instantiation of ‘struct std::_Result_of_impl<false, false, void (*)(cl1&&), cl2>’:
/usr/include/c++/4.7/type_traits:1857:12: required from ‘class std::result_of<void (*(cl2))(cl1&&)>’
/usr/include/c++/4.7/functional:1563:61: required from ‘struct std::_Bind_simple<void (*(cl2))(cl1&&)>’
/usr/include/c++/4.7/thread:133:9: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(cl1&&); _Args = {cl2&}]’
main.cpp:13:44: required from here
/usr/include/c++/4.7/type_traits:1834:9: error: invalid initialization of reference of type ‘cl1&&’ from expression of type ‘cl2’
make: *** [main.o] Error 1
template <class T> typename decay<T>::type decay_copy(T&& v)
{ return std::forward<T>(v); }