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

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 .


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.


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.