xvalues:非类类型和类类型之间的差异

时间:2016-05-05 05:55:43

标签: c++ c++11 move rvalue xvalue

考虑下面的最小例子:

#include<utility>

struct S { };

int main() {
    S s;
    std::move(s) = S{};
}

编译时没有错误。
如果我改用非类型,我会收到错误 例如,下面的代码无法编译:

#include<utility>

int main() {
    int i;
    std::move(i) = 42;
}

枚举,范围枚举等也会发生同样的情况 错误(来自GCC)是:

  

使用xvalue(右值参考)作为左值

这背后的理由是什么?

我想这是正确的,但是我想了解我能用所有类型而不是非类型的方式做到这一点的原因。

2 个答案:

答案 0 :(得分:5)

C ++允许赋值给类对象rvalues,但不能赋值为基本类型rvalues;

一个例子,

string s1, s2;
s1 + s2 = "asdf"; // ok since rvalue s1 + s2 is an object

int i1, i2;
i1 + i2 = 10;  // error, since i1 + i2 is a primitive type

同样的规则适用于您的问题。 std :: move(s)返回一个对象类型的右值,但是std :: move(i)返回一个基本类型的右值。

答案 1 :(得分:1)

<子> 我试图通过一系列标准链接来回复我自己的问题 我很确定我会写一些非常错误的东西,有人会跟我说话。
好吧,我尽力解释如何从标准中推断出问题中描述的是什么 如果需要,请随意下载,但请告诉我有什么问题,以便能够解决问题并理解错误。
谢谢。

3.9/8(类型):

  

对象类型是一种(可能是cv限定的)类型,它不是函数类型,不是引用类型,而不是 cv void。

5.2.2/10(表达式,函数调用):

  

如果结果类型是对象类型的右值引用,则函数调用是xvalue

因此std::move在任何一种情况下都是 xvalue 表达式。

5.18/3(作业):

  

如果左操作数不是类类型,则表达式被隐式转换为左操作数的cv-unqualified类型。

这不会添加有用的信息,但这是为了完整性。

4.1/2(左值到右值转换):

  

否则,如果T具有类类型,则转换复制 - 从glvalue初始化类型T的临时值,转换结果是临时的prvalue。

     

否则,glvalue指示的对象中包含的值是prvalue结果。

12.2(临时对象)完成剩下的工作。

所以,正如@xaxxon在评论中所提到的,我实际上是在尝试(让我写)42 = 0;并且它不是C ++中的有效表达式。

正如@bogdan在评论中正确指出的那样,在这种情况下要引用的标准的正确部分是5.18/1(作业):

  

所有都需要一个可修改的左值作为左操作数[...]

虽然5/25/3澄清该声明仅适用于内置运算符。