class A {};
int main() {
A() = A();
return 0;
}
Почему этот код компилируется? Не должно быть какой-то ошибки, что слева от оператора присваивания должно быть помещено lvalue? Является ли A () lvalue? версия g ++ 4.7
Ответы:
Для встроенных типов вы будете правы: встроенный оператор присваивания требует изменяемого lvalue с левой стороны.
Однако здесь используется не встроенный оператор, а перегрузка, неявно объявленная классом. Это функция-член, эквивалентная
A().operator=(A());
и функции-члены могут вызываться для rvalue .
operator=нет operator()), но не имеет отношения к вопросу. Пример ничего не делает с результатом присваивания.
A()не вызывает operator(), он создает объект типа A.
Если вы действительно хотите, вы можете сделать так, чтобы он не компилировался с 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.
Компилятор C ++ предоставляет всем классам конструктор по умолчанию, что и происходит с вашим кодом, когда вы говорите A () = A (); он просто вызывает конструктор с безымянным объектом, а функция возвращает ссылку на сконструированный объект (неявно). Это оно...