A () = A () - pourquoi compile-t-il?

85
class A {};

int main() {
 A() = A();
 return 0; 
}

Pourquoi ce code se compile-t-il? Ne devrait-il pas y avoir une erreur qui devrait être placée sur le côté gauche de l'opérateur d'affectation lvalue? Est-ce que A () lvalue? version g ++ 4.7

scdmb
la source

Réponses:

88

Pour les types intégrés, vous auriez raison: l'opérateur d'affectation intégré nécessite une lvalue modifiable sur le côté gauche.

Cependant, cela n'utilise pas l'opérateur intégré, mais la surcharge qui est implicitement déclarée par la classe. Ceci est une fonction membre, équivalente à

A().operator=(A());

et les fonctions membres peuvent être appelées sur rvalues .

Mike Seymour
la source
7
n'est-ce pas l'initialisation de la copie?
stardust
13
@Named: Non, c'est une affectation et non une initialisation.
Mike Seymour
1
@ paul23: C'est vrai (en supposant que vous operator=ne le vouliez pas operator()), mais cela n'a pas grand-chose à voir avec la question. L'exemple ne fait rien avec le résultat de l'affectation.
Mike Seymour
3
@ paul23 A()n'appelle pas operator(), il construit un objet de type A.
entre le
3
Cela ne peut pas être une initialisation car il n'y a pas de déclaration.
Kos
32

Si vous voulez vraiment, vous pouvez le faire ne pas compiler avec 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; 
}

( exemple en direct )

Notez le &et &&(aka ref-qualifiers) à la fin des déclarations des différents operator=formulaires. Cela permet de sélectionner ces déclarations pour lvalues ​​et rvalues ​​respectivement. Cependant, la version rvalue, lorsqu'elle est sélectionnée par résolution de surcharge, entraîne une mauvaise formation du programme car il est supprimé.

L'opérateur généré par défaut =, cependant, n'a pas de qualificatif de référence, ce qui signifie qu'il peut être appelé à la fois pour lvalues ​​et rvalues; c'est pourquoi le code de la question se compile, même s'il A()s'agit d'une rvalue.

R. Martinho Fernandes
la source
1

Le compilateur C ++ fournit à toutes les classes un constructeur par défaut, c'est ce qui se passe, par rapport à votre code, quand vous dites A () = A (); il appelle simplement le constructeur avec un objet sans nom et la fonction renvoie une référence à l'objet construit (implicite). C'est ça...

Praveen Kumar
la source