Por que não consigo inicializar static
membros de dados na classe?
O padrão C ++ permite que apenas integral constante estática ou tipos de enumeração sejam inicializados dentro da classe. Este é o motivo pelo qual a
pode ser inicializado, enquanto outros não.
Referência:
C ++ 03 9.4.2 Membros de dados estáticos
§4
Se um membro de dados estáticos for do tipo const integral ou const enumeração, sua declaração na definição da classe pode especificar um inicializador de constante que deve obrigatoriamente ser uma expressão de constante integral (5.19). Nesse caso, o membro pode aparecer em expressões constantes integrais. O membro ainda deve ser definido em um escopo de namespace se for usado no programa e a definição de escopo de namespace não deve conter um inicializador.
O que são tipos integrais?
C ++ 03 3.9.1 Tipos fundamentais
§7
Os tipos bool, char, wchar_t e os tipos inteiros com e sem sinal são chamados coletivamente de tipos integrais.43) Um sinônimo para o tipo integral é o tipo inteiro.
Nota de rodapé:
43) Portanto, as enumerações (7.2) não são integrais; entretanto, as enumerações podem ser promovidas a int, unsigned int, long ou unsigned long, conforme especificado em 4.5.
Gambiarra:
Você poderia usar o truque enum para inicializar um array dentro da definição de sua classe.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
Por que o padrão não permite isso?
Bjarne explica isso apropriadamente aqui :
Uma classe é normalmente declarada em um arquivo de cabeçalho e um arquivo de cabeçalho é normalmente incluído em muitas unidades de tradução. No entanto, para evitar regras complicadas do vinculador, C ++ exige que cada objeto tenha uma definição exclusiva. Essa regra seria quebrada se C ++ permitisse a definição na classe de entidades que precisavam ser armazenadas na memória como objetos.
Por que apenas static const
tipos integrais e enums são permitidos na inicialização em classe?
A resposta está oculta na citação de Bjarne, lida com atenção:
"C ++ requer que cada objeto tenha uma definição única. Essa regra seria quebrada se C ++ permitisse a definição em classe de entidades que precisavam ser armazenadas na memória como objetos."
Observe que apenas static const
inteiros podem ser tratados como constantes de tempo de compilação. O compilador sabe que o valor inteiro não mudará a qualquer momento e, portanto, pode aplicar sua própria magia e aplicar otimizações, o compilador simplesmente inline esses membros da classe, ou seja, eles não são mais armazenados na memória, pois a necessidade de serem armazenados na memória é removida , dá a tais variáveis a exceção à regra mencionada por Bjarne.
É importante notar aqui que mesmo que os static const
valores integrais possam ter inicialização em classe, tomar o endereço de tais variáveis não é permitido. Pode-se obter o endereço de um membro estático se (e somente se) ele tiver uma definição fora da classe. Isso valida ainda mais o raciocínio acima.
enums são permitidos porque valores de um tipo enumerado podem ser usados onde ints são esperados. veja a citação acima
Como isso muda no C ++ 11?
C ++ 11 relaxa a restrição até certo ponto.
C ++ 11 9.4.2 Membros de dados estáticos
§3
Se um membro de dados estáticos for do tipo const literal, sua declaração na definição de classe pode especificar um inicializador de chave ou igual no qual cada cláusula de inicialização que é uma expressão de atribuição é uma expressão constante. Um membro de dados estáticos de tipo literal pode ser declarado na definição de classe com o, constexpr specifier;
se assim for, sua declaração deve especificar um inicializador de chave ou igual no qual cada cláusula de inicialização que é uma expressão de atribuiçãoé uma expressão constante. [Nota: Em ambos os casos, o membro pode aparecer em expressões constantes. —End note] O membro ainda deve ser definido em um escopo de namespace se for usado no programa e a definição de escopo de namespace não deve conter um inicializador.
Além disso, C ++ 11 vai permitir (§12.6.2.8) um membro de dados não-estático para ser inicializado em que é declarado (na sua classe). Isso significa uma semântica do usuário muito fácil.
Observe que esses recursos ainda não foram implementados no último gcc 4.7, então você ainda pode obter erros de compilação.