O motivo é que, se a classe não tiver um construtor definido pelo usuário, pode ser POD, e a classe POD não é inicializada por padrão. Portanto, se você declarar um objeto const de POD que não foi inicializado, qual a utilidade disso? Portanto, acho que o Standard impõe essa regra para que o objeto possa realmente ser ú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!
Mas se você fizer da aula um não-POD:
struct nonPOD_A
{
nonPOD_A() {} //this makes non-POD
};
nonPOD_A a1; //initialized
const nonPOD_A a2; //initialized
Observe a diferença entre POD e não-POD.
O construtor definido pelo usuário é uma maneira de tornar a classe não POD. Existem várias maneiras de fazer isso.
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 não define o construtor definido pelo usuário. Compile-o. Ele irá compilar:
E comente a função virtual, então dá erro, conforme o esperado:
Bem, eu acho, você entendeu mal a passagem. Primeiro diz isto (§8.5 / 9):
Se nenhum inicializador for especificado para um objeto, e o objeto for do tipo de classe não-POD (possivelmente cv-qualificado) (ou array dele), o objeto deve obrigatoriamente ser inicializado por padrão; [...]
Ele fala sobre a classe não-POD, possivelmente do tipo cv qualificado . Ou seja, o objeto não-POD deve obrigatoriamente ser inicializado por padrão se não houver um inicializador especificado. E o que é inicializado por padrão ? Para não POD, a especificação diz (§8.5 / 5),
Inicializar por padrão um objeto do tipo T significa:
- se T for um tipo de classe não-POD (cláusula 9), o construtor padrão para T é chamado (e a inicialização é mal formada se T não tiver um construtor padrão acessível);
Ele simplesmente fala sobre o construtor padrão de T, seja seu definido pelo usuário ou gerado pelo compilador é irrelevante.
Se você está claro para isso, entenda o que a especificação diz a seguir ((§8.5 / 9),
[...]; se o objeto for do tipo qualificado const, o tipo de classe subjacente deve ter um construtor padrão declarado pelo usuário.
Portanto, este texto implica que o programa será malformado se o objeto for do tipo POD qualificado const e não houver um inicializador especificado (porque os POD não são inicializados por padrão):
POD p1; //uninitialized - can be useful - hence allowed
const POD p2; //uninitialized - never useful - hence not allowed - error
A propósito, ele compila bem , porque não é POD e pode ser inicializado por padrão .
a
, mas gcc-4.3.4 aceita mesmo quando você o faz (consulte ideone.com/uHvFS )