我正在尝试了解move构造函数和右值引用。 因此,我在https://www.onlinegdb.com/online_c++_compiler上尝试了此代码。 但是结果使我感到困惑。
#include <iostream>
#include <type_traits>
class A {
public:
A() { std::cout << "Constructed" << std::endl; }
A(const A& )= delete;
A(A&&) { std::cout << "Move Constructed" << std::endl; }
};
int
main ()
{
A&& a = A();
A b = a; // error: use of deleted function ‘A::A(const A&)’
//A b = static_cast<decltype(a)>(a); // This works, WTF?
std::cout << std::is_rvalue_reference<decltype(a)>::value << std::endl; // pretty sure a is rvalue reference.
return 0;
}
答案 0 :(得分:5)
您对类型和value categories感到困惑。
(重点是我的)
每个C ++表达式(具有其操作数,文字,变量名等的运算符)的特征是两个独立的属性:类型和值类别< / em> 。
作为命名变量,a
是一个左值。
以下表达式是左值表达式:
- 变量名,...
- ...
然后为A b = a;
选择复制构造函数。如您所试,static_cast<decltype(a)>(a);
会将其转换为xvalue(即rvalue);您还可以使用std::move
。
A b = std::move(a);
以下表达式是 xvalue表达式:
- 函数调用或重载的运算符表达式,其返回类型是对对象的右值引用,例如
std::move(x)
;- ...
答案 1 :(得分:1)
A&& a = A();
不会给您带来价值。将任何值视为rvalue的一种方法是您无法获取它的地址。如果可以获取它的地址,则可能是左值。 因此,就您而言
auto address_of_a = &a;
是可能的(所以a是左值)。
decltype(a)
是A &&(右值类型)。因此将类型强制转换为A &&会给您右值
A b = a;
失败,因为a是左值,因此它正在寻找A(const A&)。
A b = std::move(a); // or
A b = A{}; // rvalue
将成功,因为现在它将寻找A(A &&)
A b;
A c = A{};
b = std::move(c);
如果您将移动分配定义为在删除期间删除,则会失败
b = c;
如果定义副本分配,将会成功。
默认构造/复制构造/移动或复制分配将起作用,只要所有元素都可以被简单地复制/移动。