我知道在以下情况下编译器可以自由移动 - 构造返回值makeA(但也可以自由地删除副本或完全移动):
struct A
{
A(A&);
A(A&&);
};
A makeA()
{
A localA;
return localA;
}
Run Code Online (Sandbox Code Playgroud)
我想知道是否允许编译器通过rvalue引用A从类型的本地对象构造类型的对象(B如果它是在return语句中构造的).换句话说,在下面的例子中,是否允许编译器A为返回值选择构造函数4?
struct B { };
struct A {
A(A&); // (1)
A(A&&); // (2)
A(B&); // (3)
A(B&&); // (4)
};
A makeA()
{
B localB;
return localB;
}
Run Code Online (Sandbox Code Playgroud)
我问这个是因为在我看来,允许类型的本地对象A在return语句中被视为rvalue 的相同逻辑也应该允许任何类型的本地被视为rvalue,但我找不到任何这种例子或问题.
T.C*_*.C. 32
这种情况的规则在2011年和2014年之间发生了变化.编译器现在应该将其localB视为右值.
适用的return语句规则见§12.8[class.copy]/p32,它读入C++ 14(引用N3936,强调我的):
当满足复制/移动操作的省略标准时,但不满足异常声明,并且要复制的对象由左值指定,或者当返回语句中的表达式是(可能带有括号的)id-时表达式,用于在最内层封闭函数或lambda-expression的body或parameter-declaration-clause中声明的具有自动存储持续时间的对象, 首先执行重载决策以选择复制的构造函数,就像对象由rvalue指定一样.如果第一个重载决策失败或未执行,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv-qualified),则再次执行重载决策,将对象视为左值.
CWG问题1579添加了粗体条款,明确要求在A::A(B&&)此处调用转换移动构造函数.这在GCC 5和Clang 3.9中实现.
早在2011年,这种"尝试右值优先"规则与复制省略的标准密切相关(引用N3337):
当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由左值指定,重载决策选择复制的构造函数是首先执行,好像对象是由右值指定的.
由于复制省略必然要求两者具有相同的类型,因此该段落不适用,并且编译器必须使用A::A(B&)构造函数.
请注意,由于CWG 1579被认为是针对C++ 11的DR,因此即使在C++ 11模式下,编译器也应该实现其分辨率.