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

sky*_*ack 10 c++ move rvalue xvalue c++11

考虑下面的最小例子:

#include<utility>

struct S { };

int main() {
    S s;
    std::move(s) = S{};
}
Run Code Online (Sandbox Code Playgroud)

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

#include<utility>

int main() {
    int i;
    std::move(i) = 42;
}
Run Code Online (Sandbox Code Playgroud)

枚举,作用域枚举等也会发生同样的情况.
错误(来自GCC)是:

使用xvalue(rvalue reference)作为左值

这背后的理由是什么?

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

小智 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
Run Code Online (Sandbox Code Playgroud)

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


sky*_*ack 1

\n我正在尝试用一堆标准链接来回答我自己的问题。
\n我很确定我会写出一些非常错误的东西,并且有人会来跟我批驳。
\n好吧,我尽力解释如何从标准中推断出问题中所描述的内容。
\n如果需要,请随意投反对票,但请让我知道出了什么问题,以便能够修复答案并理解错误。
\n谢谢。\n

\n\n
\n\n

3.9/8(类型):

\n\n
\n

An\xc2\xa0对象类型\xc2\xa0 是一个(可能是 cv 限定的)类型,它不是函数类型,不是引用类型,也不是 \xc2\xa0 cv void。

\n
\n\n

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

\n\n
\n

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

\n
\n\n

因此std::move是一个x 值表达式。

\n\n

5.18/3(作业):

\n\n
\n

如果左操作数不是类类型,则表达式将隐式转换 [...] 为左操作数的 cv 非限定类型。

\n
\n\n

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

\n\n

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

\n\n
\n

否则,如果\xc2\xa0T\xc2\xa0具有类类型,则转换从泛左值复制初始化\xc2\xa0T\xc2\xa0类型的临时值,并且转换的结果是该临时值的纯右值。

\n\n

否则,左值指示的对象中包含的值是纯右值结果。

\n
\n\n

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

\n\n

因此,正如 @xaxxon 在评论中提到的,我实际上正在尝试执行(让我写)42 = 0;,但它不是 C++ 中的有效表达式。\n

\n\n

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

\n\n
\n

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

\n
\n\n

5/25/3澄清该语句仅适用于内置运算符。

\n