c++ - funciones - ¿Por qué no puedo reforzar la inicialización de una estructura derivada de otra estructura?
funciones con estructuras en c (1)
Cuando ejecuto este código:
struct X {
int a;
};
struct Y : public X {};
X x = {0};
Y Y = {0};
Yo obtengo:
error: could not convert ‘{0}’ from ‘<brace-enclosed initializer list>’ to ‘Y’
¿Por qué la inicialización de llaves funciona para la clase base pero no para la clase derivada?
Su problema tiene que ver con la inicialización agregada : struct X
es un agregado, mientras que struct Y
no lo es. Aquí está la cita estándar sobre los agregados (8.5.1):
Un agregado es una matriz o una clase (Cláusula 9) sin constructores proporcionados por el usuario (12.1), sin inicializadores ortográficos para miembros de datos no estáticos (9.2), sin miembros de datos no estáticos protegidos o privados ( Cláusula 11), sin clases base (Cláusula 10) y sin funciones virtuales (10.3).
Esta cláusula especifica que si una class
tiene una clase base, entonces no es un agregado. Aquí, la struct Y
tiene struct X
como clase base y, por lo tanto, no puede ser un tipo agregado.
Con respecto al problema particular que tiene, tome la siguiente cláusula del estándar:
Cuando un agregado se inicializa mediante una lista de inicializadores, como se especifica en 8.5.4, los elementos de la lista de inicializadores se toman como inicializadores para los miembros del agregado, en orden creciente de subíndices o miembros. Cada miembro se inicializa con copia desde la cláusula de inicializador correspondiente. Si la cláusula initializer es una expresión y se requiere una conversión de reducción (8.5.4) para convertir la expresión, el programa está mal formado.
Cuando haces X x = {0}
, la inicialización agregada se usa para inicializar a
a 0
. Sin embargo, cuando se hace Y y = {0}
, dado que la struct Y
no es un tipo agregado, el compilador buscará un constructor apropiado. Dado que ninguno de los constructores generados implícitamente (predeterminado, copiar y mover) puede hacer cualquier cosa con un solo entero, el compilador rechaza su código.
Con respecto a esta búsqueda de constructores, los mensajes de error de clang ++ son un poco más explícitos sobre lo que el compilador realmente está tratando de hacer ( ejemplo en línea ):
Y Y = {0};
^ ~~~
main.cpp:5:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from ''int'' to ''const Y &'' for 1st argument
struct Y : public X {};
^
main.cpp:5:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from ''int'' to ''Y &&'' for 1st argument
struct Y : public X {};
^
main.cpp:5:8: note: candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided
Tenga en cuenta que hay una propuesta para extender la inicialización agregada para respaldar su caso de uso, y se convirtió en C ++ 17. Si lo leo correctamente, hace que tu ejemplo sea válido con la semántica que esperas. Entonces ... solo debe esperar un compilador compatible con C ++ 17.