A() = A() - зачем он компилируется?

class A {};

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

Почему этот код компилируется? Должна ли быть некоторая ошибка, которая на левой стороне оператора присваивания должна быть установлена ​​lvalue? Является ли A() lvalue? g++ 4.7 версия

Ответ 1

Для встроенных типов вы должны быть правильными: для встроенного оператора присваивания требуется модифицируемое значение lvalue с левой стороны.

Однако это не использует встроенный оператор, а перегрузку, которая неявно объявляется классом. Это функция-член, эквивалентная

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

а функции-члены можно вызывать на r значениях.

Ответ 2

Если вы действительно этого хотите, вы можете сделать его не компилируемым с С++ 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; 
}

(живой пример)

Обратите внимание на & и && (aka ref-qualifiers) в конце объявлений различных форм operator=. Это позволяет отображать эти объявления для lvalues ​​и rvalues ​​соответственно. Тем не менее, версия rvalue, когда она выбрана с помощью разрешения перегрузки, приводит к плохому формированию программы, поскольку она удалена.

Порожденный по умолчанию оператор =, однако, не имеет никакого ref-определителя, то есть он может быть вызван как для lvalues, так и для rvalues; почему код в вопросе компилируется, хотя A() является rvalue.

Ответ 3

Компилятор С++ предоставляет всем классам конструктор по умолчанию, что то, что происходит в отношении вашего кода, когда вы говорите А() = A(); он просто вызывает конструктор с безымянным объектом, и функция возвращает ссылку на построенный объект (неявный). Что это...