85
class A {};

int main() {
 A() = A();
 return 0; 
}

为什么这段代码会编译?不应该有一些错误应该在赋值运算符的左侧放置左值吗?A() 是左值吗?g++ 4.7版本

4

3 回答 3

88

对于内置类型,您是正确的:内置赋值运算符需要在左侧有一个可修改的左值。

但是,这不是使用内置运算符,而是使用类隐式声明的重载。这是一个成员函数,相当于

A().operator=(A());

并且可以在rvalues上调用成员函数。

于 2013-04-30T15:11:52.407 回答
32

如果你真的想要,你可以让它不使用 C++11 编译:

class A {
    template <typename T>
    void operator=(T&&) && = delete; // no op= for rvalues

    // generate other special members normally
    A() = default;
    A(A const&) = default;
    A(A&&) = default;
    ~A() = default;
    // op= only for lvalues
    A& operator=(A&&) & = default;
    A& operator=(A const&) & = default;
};

int main() {
 A() = A(); // error
 return 0; 
}

活生生的例子

请注意各种形式声明末尾的&and (也称为 ref 限定符)。这使得这些声明分别被选择用于左值和右值。但是,当通过重载决议选择右值版本时,会导致程序格式错误,因为它已被删除。&&operator=

然而,默认生成的 operator= 没有任何 ref 限定符,这意味着它可以为左值和右值调用;这就是问题中的代码编译的原因,即使它A()是一个右值。

于 2013-04-30T15:14:28.377 回答
1

C++ 编译器为所有类提供了一个默认构造函数,当你说 A()=A(); 时,就你的代码而言,这就是发生的事情。它只是使用无名对象调用构造函数,并且函数返回对构造对象的引用(隐式)。而已...

于 2013-05-01T02:16:06.400 回答