class A {};
int main() {
A() = A();
return 0;
}
Чому цей код компілюється? Чи не повинно бути помилок, які ліворуч від оператора присвоювання слід розміщувати lvalue? Чи є значення A () l? версія g ++ 4.7
Відповіді:
Для вбудованих типів ви мали б рацію: вбудований оператор присвоєння вимагає змінної lvalue зліва.
Однак тут використовується не вбудований оператор, а перевантаження, яке неявно оголошено класом. Це функція-член, еквівалентна
A().operator=(A());
а функції-члени можна викликати на rvalues .
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;
}
( живий приклад )
Зверніть увагу на &та &&(також відомі кваліфікатори) у кінці декларацій різних operator=форм. Це змушує ці декларації бути обраними для lvalues та rvalues відповідно. Однак версія rvalue, вибрана за допомогою дозволу на перевантаження, спричиняє неправильну форму програми, оскільки вона видаляється.
Типово згенерований оператор =, однак, не має жодного кваліфікатора ref, тобто його можна викликати як для lvalues, так і для rvalues; тому код у питанні компілюється, хоча A()це і є значенням.
Компілятор C ++ надає всім класам конструктор за замовчуванням, ось що відбувається стосовно вашого коду, коли ви говорите A () = A (); він просто викликає конструктор з безіменним об'єктом, а функція повертає посилання на побудований об'єкт (неявний). Це воно...