La razón es que si la clase no tiene un constructor definido por el usuario, entonces puede ser POD y la clase POD no se inicializa por defecto. Entonces, si declaras un objeto constante de POD que no está inicializado, ¿para qué sirve? Así que creo que el Estándar hace cumplir esta regla para que el objeto pueda ser realmente útil.
struct POD
{
int i;
};
POD p1; //uninitialized - but don't worry we can assign some value later on!
p1.i = 10; //assign some value later on!
POD p2 = POD(); //initialized
const POD p3 = POD(); //initialized
const POD p4; //uninitialized - error - as we cannot change it later on!
Pero si hace que la clase no sea POD:
struct nonPOD_A
{
nonPOD_A() {} //this makes non-POD
};
nonPOD_A a1; //initialized
const nonPOD_A a2; //initialized
Tenga en cuenta la diferencia entre POD y no POD.
El constructor definido por el usuario es una forma de hacer que la clase no sea POD. Hay varias formas de hacerlo.
struct nonPOD_B
{
virtual void f() {} //virtual function make it non-POD
};
nonPOD_B b1; //initialized
const nonPOD_B b2; //initialized
Observe que nonPOD_B no define un constructor definido por el usuario. Compílelo. Compilará:
Y comenta la función virtual, luego da error, como se esperaba:
Bueno, creo que no entendiste el pasaje. Primero dice esto (§8.5 / 9):
Si no se especifica ningún inicializador para un objeto, y el objeto es de tipo de clase no POD (posiblemente calificado por cv) (o matriz del mismo), el objeto se inicializará por defecto; [...]
Habla de una clase no POD posiblemente de tipo calificado para cv . Es decir, el objeto que no es POD se inicializará por defecto si no se especifica ningún inicializador. ¿Y qué se inicializa por defecto ? Para no POD, la especificación dice (§8.5 / 5),
Inicializar por defecto un objeto de tipo T significa:
- si T es un tipo de clase que no es POD (cláusula 9), se llama al constructor por defecto para T (y la inicialización está mal formada si T no tiene un constructor por defecto accesible);
Simplemente habla del constructor predeterminado de T, ya sea que sea definido por el usuario o generado por el compilador es irrelevante.
Si tiene claro esto, entienda lo que dice la siguiente especificación ((§8.5 / 9),
[...]; si el objeto es de tipo calificado const, el tipo de clase subyacente tendrá un constructor predeterminado declarado por el usuario.
Entonces, este texto implica que el programa estará mal formado si el objeto es de tipo POD calificado const , y no hay un inicializador especificado (porque los POD no están inicializados por defecto):
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful - hence not allowed - error
Por cierto, esto se compila bien , porque no es POD y puede inicializarse por defecto .
a
, pero gcc-4.3.4 la acepta incluso cuando lo haga (consulte ideone.com/uHvFS )