MSVC++ 2013 似乎允许对临时对象进行赋值,有效地将它们视为左值

MSVC++ 2013 seems to allow assignments to temporary objects, effectively treating them as lvalues

我在 MSVC++ 中遇到过这个 "feature",现在我不确定这是一个错误还是我对 C++ 中 lvalues/rvalues 的理解完全错误。

我已经添加了一些非常简单的代码来说明,但基本上问题是 MSVC++ 2013(基本和 2013 年 11 月 CTP 编译器)允许分配给临时对象,这实际上应该是右值,因此不允许任何编译时的赋值尝试。

#include <iostream>

struct account {
    int value;

    explicit account(int v) : value{ v } { 
        std::cout << "account ctor: " << value << std::endl; 
    }
    account(const account & acc) : value{ acc.value } { 
        std::cout << "account copy ctor" << std::endl; 
    }
    account(account && acc) : value{ acc.value } { 
        std::cout << "account move ctor" << std::endl; 
    }
    account & operator=(const account & acc) {
        value = acc.value;
        std::cout << "account copy assign" << std::endl;
        return *this;
    }
    account & operator=(account && acc) {
        value = acc.value;
        std::cout << "account move assign" << std::endl;
        return *this;
    }   
};

int get_int() { return 42; }

account get_account() {
    return account(123);
}

int main() {
    //get_int() = 5;    // this predictably fails to compile
                        // with '=' : left operand must be l-value

    // everything below succeeds
    get_account() = account(42);    // console trace for this 
                                    // account ctor: 42
                                    // account ctor: 123
                                    // account move assign

    account(123) = account(42);     // console trace same as above

    account acc(0);                 // account ctor: 0
    account(42) = acc;              // account ctor: 42
                                    // account copy assign

    get_account() = acc;            // console trace same as above
}

肯定 get_account() = acc;account(42) = acc; 不是 C++ 标准规定的行为?! get_account()account(42) 都应该产生右值,根据定义,右值不允许赋值。

顺便提一下,根据 lvalue/rvalue 限定符

重载成员函数
...
void memberFn() const &;
void memberFn() &&;
...

2013 年 11 月支持的 CTP 无法正常工作或根本无法工作。我认为这是未能识别右值的结果,因此 this 始终是左值。

PS 不幸的是,我没有机会用其他编译器测试它。

根据我的理解,这是完全有效的 C++11。

对纯右值的内置赋值是被禁止的。

来自 [5, expr]:

Note: Operators can be overloaded, that is, given meaning when applied to expressions of class type (Clause 9) or enumeration type (7.2). Uses of overloaded operators are transformed into function calls as described in 13.5. Overloaded operators obey the rules for syntax specified in Clause 5, but the requirements of operand type, value category, and evaluation order are replaced by the rules for function call.

所以对

的要求
get_account() = account(42);

与任何其他成员函数调用相同

get_account().foo_bar(account(42));

这是有道理的,因为它只是

的一个更好的语法
get_account().operator=(account(42));

关于左值和右值的第 3.10 节清楚地说明了这一点 [basic.lval]:

For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return types.