ejemplo define constantes c++ c++11 const constexpr

define - x[0]== 1 expresión constante en C++ 11 cuando x es constante int[]?



const en c (2)

¿Está mal formado el siguiente programa de C ++ 11?

const int x[] = {1,2,3}; static_assert(x[0] == 1, "yay"); int main() {}

gcc y clang parecen pensar que sí, pero ¿por qué x[0] == 1 una expresión constante?

x[0] == 1 subscript operator *(x+0) == 1 array-to-pointer conversion (int* p = x) *(p+0) == 1 pointer addition *p == 1 indirection (lvalue y = x[0]) y == 1 lvalue-to-rvalue conversion:

un glvalue no volátil (sí, x [0] es un glvalue y no volátil) de integral (sí, tiene tipo const int) o tipo de enumeración que se refiere a un objeto const no volátil (sí, tiene tipo const int) con una inicialización anterior (sí inicializada con 1), inicializada con una expresión constante (sí 1 es expresión constante)

Parece cierto, el primer elemento de la matriz x satisface estas condiciones.

1 == 1

?

¿Es este un error de compilación, defecto estándar, o me falta algo?

¿Qué parte de 5.19 [expr.const] dice que esta no es una expresión constante?


En 5.19:

Una expresión es una expresión constante a menos que incluya uno de los siguientes [...]:

  • una conversión de lvalue a rvalue (4.1) a menos que se aplique a

    • un valor de tipo integral o de enumeración que hace referencia a un objeto const no volátil con una inicialización anterior, inicializado con una expresión constante, o
    • un valor de tipo literal que se refiere a un objeto no volátil definido con constexpr, o que se refiere a un subobjeto de tal objeto, o
    • un valor de tipo literal que hace referencia a un objeto temporal no volátil inicializado con una expresión constante

En pocas palabras, la conversión de valor a valor r solo se puede realizar en expresiones constantes si:

  • una declaración integral constante (o enumeración) inicializada con una constante: const int x = 3; .
  • una declaración con constexpr : constexpr int x[] = {1,2,3}; .
  • un objeto temporal inicializado con una expresión constante ...

Su ejemplo incluye la conversión de valores a valores, pero no tiene ninguna de estas excepciones, por lo que x no es una expresión constante. Si, sin embargo, lo cambias a:

constexpr int x[] = {1,2,3}; static_assert(x[0] == 1, "yay"); int main() {}

Entonces todo está bien.


Por la redacción actual de la norma es un error del compilador, y el programa está bien formado. Ahora se está considerando si debería ser un defecto estándar, ya que sería difícil de implementar.

Para una explicación detallada ver:

https://groups.google.com/a/isocpp.org/forum/?fromgroups#!topic/std-discussion/Nv5_2dCHm6M

Informe copiado abajo:

La redacción actual del funcionario de C ++ 11 hasta N3690 inclusive tiene lo siguiente:

Una expresión condicional e es una expresión constante central a menos que la evaluación de e evalúe una de las siguientes expresiones:

  • una conversión de lvalue a rvalue (4.1) a menos que se aplique a
    • un valor no volátil de tipo integral o de enumeración que hace referencia a un objeto const no volátil con una inicialización anterior, inicializado con una expresión constante

La siguiente declaración a nivel global:

const int x[2] = {42, 43};

define una matriz de 2 objetos const const, inicializada en lista con {42, 43}

En 8.5.1 [dcl.init.aggr] / 2:

Cuando un agregado se inicializa mediante una lista de inicializadores, como se especifica en 8.5.4, los elementos de la lista de inicializadores se toman como inicializadores para los miembros del agregado, al aumentar el subíndice o el orden de los miembros.

Así que el inicializador del objeto del primer elemento es 42 y el inicializador del objeto del segundo elemento es 43 .

La expresión *x es un lvalue y una expresión constante de núcleo. Implica una conversión de matriz a puntero y una indirección, ninguna de las cuales descalifica la expresión como una expresión de la constante central. La expresión glvalue se refiere al primer elemento objeto de x . *x es un glvalor no volátil de tipo integral (const int) que se refiere a un objeto const no volátil con una inicialización precedente e inicializado con la expresión constante 42 .

Por lo tanto, se permite una conversión de valor de l a valor r aplicado al valor de gl *x en una expresión constante, por lo que lo siguiente está bien formado:

constexpr int y = *x;

Ni gcc ni clang trunk actualmente aceptan esto como una expresión constante, a pesar de que están bien formados de acuerdo con el estándar.

¿Está previsto esto?

Un programa completo de demostración:

const int x[2] = {42, 43}; constexpr int y = *x; int main() {}

Las implementaciones también fallan con el valor equivalente x[0] también.