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

85
class A {};

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

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

scdmb
источник

Ответы:

88

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

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

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

и функции-члены могут вызываться для rvalue .

Майк Сеймур
источник
7
разве это не инициализация копии?
stardust
13
@Named: Нет, это назначение, а не инициализация.
Майк Сеймур
1
@ paul23: Это правда (если вы имеете в виду, что operator=нет operator()), но не имеет отношения к вопросу. Пример ничего не делает с результатом присваивания.
Майк Сеймур
3
@ paul23 A()не вызывает operator(), он создает объект типа A.
Interjay
3
Это не может быть инициализация, потому что нет объявления.
Кос
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; 
}

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

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

Однако сгенерированный по умолчанию оператор = не имеет квалификатора ref, то есть его можно вызывать как для lvalue, так и для rvalue; вот почему код в вопросе компилируется, даже если A()это rvalue.

Р. Мартиньо Фернандес
источник
1

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

Правин Кумар
источник