class A {};
int main() {
A() = A();
return 0;
}
Dlaczego ten kod się kompiluje? Czy nie powinno być błędu polegającego na umieszczeniu po lewej stronie operatora przypisania lwartość? Czy A () lwartość? Wersja g ++ 4.7
Odpowiedzi:
Dla typów wbudowanych, byłbyś poprawne: wbudowany operator przypisania wymaga modyfikowalna lwartość na lewym skrzydle.
Jednak nie jest to użycie operatora wbudowanego, ale przeciążenie, które jest niejawnie zadeklarowane przez klasę. To jest funkcja składowa, równoważna
A().operator=(A());
a funkcje składowe mogą być wywoływane na rvalues .
operator=nie masz na myśli operator()), ale nie ma to wiele wspólnego z pytaniem. Przykład nie robi nic z wynikiem przypisania.
A()nie wywołuje operator(), tworzy obiekt typu A.
Jeśli naprawdę chcesz, możesz uniemożliwić kompilację z 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;
}
( przykład na żywo )
Zwróć uwagę na &and &&(aka ref-Qualifiers) na końcu deklaracji różnych operator=form. To sprawia, że te deklaracje są wybierane odpowiednio dla lvalues i rvalues. Jednak wersja rvalue wybrana przez rozwiązanie przeciążenia powoduje, że program jest nieprawidłowo sformułowany, ponieważ został usunięty.
Domyślnie wygenerowany operator = nie ma jednak żadnego kwalifikatora ref, co oznacza, że można go wywołać zarówno dla lvalues, jak i rvalues; dlatego kod w pytaniu kompiluje się, mimo że A()jest wartością r.
Kompilator C ++ dostarcza wszystkim klasom domyślnego konstruktora, to właśnie się dzieje, w odniesieniu do twojego kodu, kiedy powiesz A () = A (); po prostu wywołuje konstruktor z bezimiennym obiektem, a funkcja zwraca odniesienie do skonstruowanego obiektu (niejawne). Otóż to...