A () = A () - dlaczego się kompiluje?

85
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

scdmb
źródło

Odpowiedzi:

88

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 .

Mike Seymour
źródło
7
czy nie jest to inicjalizacja kopii?
Stardust
13
@Named: Nie, to przypisanie, a nie inicjalizacja.
Mike Seymour
1
@ paul23: To prawda (zakładając, że operator=nie masz na myśli operator()), ale nie ma to wiele wspólnego z pytaniem. Przykład nie robi nic z wynikiem przypisania.
Mike Seymour
3
@ paul23 A()nie wywołuje operator(), tworzy obiekt typu A.
interjay
3
Nie może to być inicjalizacja, ponieważ nie ma deklaracji.
Kos
32

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.

R. Martinho Fernandes
źródło
1

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...

Praveen Kumar
źródło