为什么右值引用根据类型的不同表现不同?

WIL*_*RIL 4 c++ rvalue rvalue-reference c++11

我正在阅读有关 C++ 右值引用和表达式的值类别的内容。但是,我无法理解(从左值、x值、纯右值的角度)为什么以下代码按预期工作:

struct S {
    int a;
};

S&& t(S& a) {
    return (S&&)a;
}

int main()
{   
    S s = { 1 };
    t(s) = S{ 2 };
    cout << s.a; // prints 2
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

而以下代码甚至无法编译,并显示error: using rvalue as lvalue

int&& t(int& a) {
    return (int&&)(a);
}

int main()
{   
    int s = 1;
    t(s) = 2; // error
    std::cout << s;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

对我来说,在这两种情况下都t(s)应该表现为xvalue. 因此,它可以出现在赋值运算符的左侧(在此上下文中不讨论运算符覆盖)。标准字面意思是,调用返回类型为右值引用的函数的结果是 xvalue。为什么 forint和 for 的行为不同struct S?标准(或 cppreference.com)是否以任何方式预测了这种行为?我无法意识到这个场景中的想法顺序是什么。

我期望打印第二个代码,2因为s最初保存的内存位置1将被.2rvalue reference

o_o*_*tle 6

正如标准所指出的:

\n
\n

[注 1:...例如,内置赋值运算符期望左操作数是左值,右操作数是纯右值,并产生左值作为结果。用户定义的运算符是函数,它们期望和产生的值的类别由它们的参数和返回类型决定。\xe2\x80\x94 尾注]

\n
\n

也就是说,operator=使用的S实际上是编译器隐式生成的函数。所以,默认的就像:

\n
S& operator=(const S&) { /*...*/ return *this; }\nS& operator=(S&&){ /*...*/ return *this; }\n
Run Code Online (Sandbox Code Playgroud)\n

这将允许用户调用该函数,其行为与内置运算符不同;但是,如果您通过引用限定符显式禁用它:

\n
S& operator=(const S&) & { /*...*/ return *this; }\nS& operator=(S&&) & { /*...*/ return *this; }\n// Or e.g. S& operator=(S&&) & =default;\n
Run Code Online (Sandbox Code Playgroud)\n

那么该函数只能用于左值。

\n