c++ - Inicializador de expresión constante para miembro de clase estática de tipo double
c++11 c++14 (2)
En C ++ 11 y C ++ 14, ¿por qué necesito
constexpr
en el siguiente fragmento de
constexpr
:
class Foo {
static constexpr double X = 0.75;
};
mientras que este produce un error de compilación:
class Foo {
static const double X = 0.75;
};
y (más sorprendentemente) esto se compila sin errores?
class Foo {
static const double X;
};
const double Foo::X = 0.75;
En C ++ 03 solo se nos permitió proporcionar un inicializador en clase para variables miembro estáticas de integral constante de tipos de enumeración, en C ++ 11 podríamos inicializar un miembro estático de tipo literal en clase usando constexpr. Esta restricción se mantuvo en C ++ 11 para las variables const, principalmente para la compatibilidad con C ++ 03, podemos ver esto desde el problema cerrado 1826: punto flotante const en expresiones constantes que dice:
Un entero constante inicializado con una constante se puede usar en expresiones constantes, pero una variable de coma flotante constante inicializada con una constante no puede. Esto fue intencional, para ser compatible con C ++ 03 mientras se fomentaba el uso constante de constexpr. Sin embargo, algunas personas han encontrado sorprendente esta distinción.
CWG terminó cerrando esta solicitud como no un defecto ( NAD ), básicamente diciendo:
que los programadores que desean valores de coma flotante para participar en expresiones constantes deben usar constexpr en lugar de const.
Para la referencia
N1804
el borrador de estándar más cercano a C ++ 03 disponible públicamente en la sección
9.4.2
[class.static.data]
dice:
Si un miembro de datos estáticos es de tipo const integral o de enumeración const, 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 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 contendrá un inicializador.
y el borrador de la sección estándar C ++ 11
9.4.2
[class.static.data]
dice:
Si un miembro de datos estáticos de constante no volátil es de tipo integral o de enumeración, su declaración en la definición de clase puede especificar un inicializador de paréntesis o igual en el que cada cláusula de inicializador que es una expresión de asignación es una expresión constante (5.19) . Un miembro de datos estáticos de tipo literal se puede declarar en la definición de clase con el especificador constexpr; en caso afirmativo, su declaración especificará un inicializador de paréntesis o igual en el que cada cláusula de inicializador que sea una expresión de asignación es una expresión constante. [...]
esto es más o menos lo mismo en el borrador del estándar C ++ 14.
Las "definiciones" de const estáticas en clase son en realidad declaraciones. Cuando se define una variable, el compilador asigna memoria para esa variable, pero ese no es el caso aquí, es decir, tomar la dirección de estas cosas estáticas const-in-class está mal formado, NDR.
Se supone que estas cosas deben trabajarse en el código, pero eso no es tan fácil de hacer con los tipos de coma flotante, por lo tanto, no está permitido.
Al definir sus variables constantes estáticas fuera de la clase, le está indicando al compilador que esta es una definición real, una instancia real con ubicación de memoria.