A () = A () - ¿por qué se compila?

85
class A {};

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

¿Por qué se compila este código? ¿No debería haber algún error que en el lado izquierdo del operador de asignación debería colocarse lvalue? ¿Es A () lvalor? versión g ++ 4.7

scdmb
fuente

Respuestas:

88

Para los tipos integrados, estaría en lo correcto: el operador de asignación integrado requiere un lvalue modificable en el lado izquierdo.

Sin embargo, esto no usa el operador integrado, sino la sobrecarga que la clase declara implícitamente. Esta es una función miembro, equivalente a

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

y las funciones miembro se pueden llamar en rvalues .

Mike Seymour
fuente
7
¿No es copia de inicialización?
stardust
13
@Named: No, es una asignación, no una inicialización.
Mike Seymour
1
@ paul23: Eso es cierto (suponiendo que operator=no lo quieras decir operator()), pero no tiene mucho que ver con la pregunta. El ejemplo no hace nada con el resultado de la tarea.
Mike Seymour
3
@ paul23 A()no llama operator(), construye un objeto de tipo A.
interjay
3
No puede ser una inicialización porque no hay declaración.
Kos
32

Si realmente lo desea, puede hacer que no se compile con 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; 
}

( ejemplo vivo )

Tenga en cuenta los &y &&(también conocidos como calificadores de referencia) al final de las declaraciones de los distintos operator=formularios. Esto hace que esas declaraciones se seleccionen para lvalues ​​y rvalues ​​respectivamente. Sin embargo, la versión rvalue, cuando se selecciona por resolución de sobrecarga, hace que el programa tenga un formato incorrecto porque se elimina.

El operador generado predeterminado =, sin embargo, no tiene ningún calificador de referencia, lo que significa que se puede llamar tanto para lvalues ​​como para rvalues; es por eso que el código de la pregunta se compila, aunque A()es un rvalue.

R. Martinho Fernandes
fuente
1

El compilador de C ++ proporciona a todas las clases un constructor predeterminado, eso es lo que sucede, con respecto a su código, cuando dice A () = A (); simplemente invoca al constructor con un objeto sin nombre y la función devuelve una referencia al objeto construido (implícito). Eso es...

Praveen Kumar
fuente