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

xvalues: differences between non class types and class types

考虑下面的最小示例:

#include<utility>

struct S { };

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

编译没有错误。
如果我改用非 class 类型,则会出现错误。
例如,下面的代码无法编译:

#include<utility>

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

枚举、作用域枚举等也是如此。
错误(来自 GCC)是:

using xvalue (rvalue reference) as lvalue

这背后的原理是什么?

我想这是对的,但我想了解我可以对除非 class 以外的所有类型执行此操作的原因。

C++ 允许对 class 对象右值进行赋值,但不允许对基本类型右值进行赋值;

一个例子,

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) returns 对象类型的右值,但 std::move(i) returns 基本类型的右值。

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


3.9/8(类型):

An object type is a (possibly cv-qualified) type that is not a function type, not a reference type, and not cv void.

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

A function call is [...] an xvalue if the result type is an rvalue reference to object type

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

5.18/3(赋值):

If the left operand is not of class type, the expression is implicitly converted [...] to the cv-unqualified type of the left operand.

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

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

Otherwise, if T has a class type, the conversion copy-initializes a temporary of type T from the glvalue and the result of the conversion is a prvalue for the temporary.

Otherwise, the value contained in the object indicated by the glvalue is the prvalue result.

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

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

正如@bogdan 在评论中正确指出的那样,在这种情况下要参考的标准的右侧部分是 5.18/1(赋值):

All require a modifiable lvalue as their left operand [...]

虽然 5/2 and 5/3 阐明该声明仅适用于内置运算符。