¿Por qué no puedo inicializar static
miembros de datos en clase?
El estándar C ++ permite que solo se inicialicen tipos de enumeración o integrales constantes estáticas dentro de la clase. Esta es la razón por la que a
se permite la inicialización mientras que otras no.
Referencia:
C ++ 03 9.4.2 Miembros de datos estáticos
§4
Si un miembro de datos estáticos es de tipo enumeración constante o integral, su declaración en la definición de clase puede especificar un inicializador constante que será una expresión constante integral (5.19). En ese caso, el miembro puede aparecer en expresiones constantes integrales. El miembro seguirá estando definido en un ámbito de espacio de nombres si se utiliza en el programa y la definición del ámbito de espacio de nombres no deberá contener un inicializador.
¿Qué son los tipos integrales?
C ++ 03 3.9.1 Tipos fundamentales
§7
Los tipos bool, char, wchar_t y los tipos enteros con signo y sin signo se denominan colectivamente tipos integrales.43) Un sinónimo de tipo integral es tipo entero.
Nota:
43) Por tanto, las enumeraciones (7.2) no son integrales; sin embargo, las enumeraciones se pueden promover a int, unsigned int, long o unsigned long, como se especifica en 4.5.
Solución alterna:
Puede usar el truco de la enumeración para inicializar una matriz dentro de la definición de su clase.
class A
{
static const int a = 3;
enum { arrsize = 2 };
static const int c[arrsize] = { 1, 2 };
};
¿Por qué la Norma no lo permite?
Bjarne explica esto acertadamente aquí :
Por lo general, una clase se declara en un archivo de encabezado y un archivo de encabezado generalmente se incluye en muchas unidades de traducción. Sin embargo, para evitar reglas complicadas del enlazador, C ++ requiere que cada objeto tenga una definición única. Esa regla se rompería si C ++ permitiera la definición en clase de entidades que deben almacenarse en la memoria como objetos.
¿Por qué solo se static const
permiten tipos integrales y enumeraciones en clase?
La respuesta está oculta en la cita de Bjarne, léala atentamente,
"C ++ requiere que cada objeto tenga una definición única. Esa regla se rompería si C ++ permitiera la definición en clase de las entidades que deben almacenarse en la memoria como objetos".
Tenga en cuenta que solo los static const
números enteros pueden tratarse como constantes de tiempo de compilación. El compilador sabe que el valor entero no cambiará en ningún momento y, por lo tanto, puede aplicar su propia magia y aplicar optimizaciones, el compilador simplemente integra dichos miembros de clase, es decir, ya no se almacenan en la memoria, ya que se elimina la necesidad de ser almacenados en la memoria. , otorga a tales variables la excepción a la regla mencionada por Bjarne.
Vale la pena señalar aquí que incluso si los static const
valores integrales pueden tener In-Class Initialization, no se permite tomar la dirección de tales variables. Se puede tomar la dirección de un miembro estático si (y solo si) tiene una definición fuera de clase. Esto valida aún más el razonamiento anterior.
Las enumeraciones están permitidas porque se pueden usar valores de un tipo enumerado donde se esperan ints. ver cita anterior
¿Cómo cambia esto en C ++ 11?
C ++ 11 relaja la restricción hasta cierto punto.
C ++ 11 9.4.2 Miembros de datos estáticos
§3
Si un miembro de datos estáticos es de tipo literal const, su declaración en la definición de clase puede especificar un inicializador-llave-o-igual en el que cada cláusula-inicializadora que es una expresión-asignación es una expresión constante. Un miembro de datos estáticos de tipo literal se puede declarar en la definición de clase con el constexpr specifier;
si es así, su declaración especificará un inicializador de llave o igual en el que cada cláusula de inicializador que es una expresión de asignaciónes una expresión constante. [Nota: en ambos casos, el miembro puede aparecer en expresiones constantes. —Nota final] El miembro aún se definirá en un ámbito de espacio de nombres si se utiliza en el programa y la definición del ámbito de espacio de nombres no debe contener un inicializador.
También, C ++ 11 será permitir (§12.6.2.8) un miembro de datos no estático para inicializar donde se declara (en su clase). Esto significará una semántica de usuario mucho más sencilla.
Tenga en cuenta que estas funciones aún no se han implementado en la última versión de gcc 4.7, por lo que es posible que aún obtenga errores de compilación.