A () = A () - por que ele compila?

85
class A {};

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

Por que este código compila? Não deveria haver algum erro que no lado esquerdo do operador de atribuição deve ser colocado lvalue? É A () lvalue? versão g ++ 4.7

scdmb
fonte

Respostas:

88

Para os tipos internos, você estaria correto: o operador de atribuição interno requer um lvalue modificável no lado esquerdo.

No entanto, isso não está usando o operador integrado, mas a sobrecarga que é declarada implicitamente pela classe. Esta é uma função de membro, equivalente a

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

e as funções de membro podem ser chamadas em rvalues .

Mike Seymour
fonte
7
não é a inicialização da cópia?
stardust
13
@Named: Não, é atribuição, não inicialização.
Mike Seymour
1
@ paul23: Isso é verdade (supondo que você operator=não queira operator()), mas não tem muito a ver com a pergunta. O exemplo não faz nada com o resultado da atribuição.
Mike Seymour
3
@ paul23 A()não chama operator(), ele constrói um objeto do tipo A.
intervalo de
3
Não pode ser uma inicialização porque não há declaração.
Kos
32

Se você realmente quiser, pode fazer com que ele não seja compilado com 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; 
}

( exemplo ao vivo )

Observe o &e &&(também conhecido como qualificadores ref) no final das declarações dos vários operator=formulários. Isso faz com que essas declarações sejam selecionadas para lvalues ​​e rvalues ​​respectivamente. No entanto, a versão rvalue, quando selecionada pela resolução de sobrecarga, faz com que o programa fique malformado porque foi excluído.

O operador padrão gerado =, entretanto, não possui nenhum qualificador ref, o que significa que pode ser chamado para lvalues ​​e rvalues; é por isso que o código da pergunta é compilado, embora A()seja um rvalue.

R. Martinho Fernandes
fonte
1

O compilador C ++ fornece a todas as classes um construtor padrão, é o que acontece, com relação ao seu código, quando você diz A () = A (); ele apenas invoca o construtor com um objeto sem nome e a função retorna a referência ao objeto construído (implícito). É isso aí...

Praveen Kumar
fonte