c++ - ejemplos - awk unix
int a=1, es un || 1 una expresión constante? (3)
N4527 5.20 [expr.const] p5
Una expresión constante es una expresión constante núcleo glvalue cuyo valor se refiere a una entidad que es un resultado permitido de una expresión constante (como se define a continuación) o una expresión constante prvalue core cuyo valor es un objeto donde, para ese objeto y sus subobjetos :
- cada miembro de datos no estáticos de tipo de referencia se refiere a una entidad que es un resultado permitido de una expresión constante, y
- si el objeto o subobjeto es de tipo puntero, contiene la dirección de un objeto con duración de almacenamiento estático, la dirección más allá del final de dicho objeto (5.7), la dirección de una función o un valor de puntero nulo.
Una entidad es un resultado permitido de una expresión constante si es un objeto con una duración de almacenamiento estática que no es un objeto temporal o es un objeto temporal cuyo valor satisface las restricciones anteriores, o es una función.
void foo(){
int a = 1;
int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
switch(1){
case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
;
}
}
Es a || 1
a || 1
una expresión constante ?
N4527 5.20 [expr.const] p2
Una expresión condicional e es una expresión constante central a menos que la evaluación de e, siguiendo las reglas de la máquina abstracta (1.9), evalúe una de las siguientes expresiones:
(2.7) - conversión de valor l a valor r (4.1) a menos que se aplique a
(2.7.1) - un glvalue no volátil de tipo integral o de enumeración que se refiere a un objeto const completo no volátil con una inicialización precedente, inicializado con una expresión constante, o
(2.7.2) - un glvalue no volátil que se refiere a un subobjeto de un literal de cadena (2.13.5), o
(2.7.3) - un glvalue no volátil que se refiere a un objeto no volátil definido con constexpr, o que se refiere a un subobjeto no mutable de tal objeto, o
(2.7.4) - un glvalue no volátil de tipo literal que se refiere a un objeto no volátil cuyo tiempo de vida comenzó dentro de la evaluación de e;
Es a || 1
a || 1
una expresión constante de núcleo ?
Repitiendo tu cita:
(2.7) - conversión de valor l a valor r (4.1) a menos que se aplique a
(2.7.1) - un glvalue no volátil de tipo integral o de enumeración que se refiere a un objeto const completo no volátil con una inicialización precedente, inicializado con una expresión constante, o
a
implica una conversión de lvalue a rvalue. Dado que a
no es un objeto const, eso significa que a
no es una expresión constante del núcleo; por lo tanto a || 1
a || 1
tampoco es uno.
Sin embargo si su código fuera:
const int a = 1;
entonces a || 1
a || 1
sería una expresión constante del núcleo.
Si el compilador comprueba toda la cadena de asignación, puede determinar que "a || 1" es una expresión constante. Sin embargo, como a es una variable, a menos que el compilador compruebe que a no se ha asignado, no tiene forma de saber que "a || 1" es una expresión constante.
a
no es una expresión constante ( vea la cita estándar a continuación ) y por lo tanto:
a || 1
Tampoco es una expresión constante, aunque sabemos que la expresión tiene que evaluar a verdadero, el estándar requiere una evaluación de izquierda a derecha aquí y no veo excepciones que permitan al compilador omitir la conversión de valor-a-valor de a
.
pero:
const int a = 1;
Podría usarse en una expresión constante porque cae bajo la excepción de 5.20p2
( énfasis mío ):
una conversión de lvalue a rvalue (4.1) a menos que se aplique a
- un glvalue no volátil de tipo integral o de enumeración que se refiere a un objeto const completo no volátil con una inicialización precedente, inicializado con una expresión constante , o
- un glvalue no volátil que se refiere a un subobjeto de un literal de cadena (2.13.5), o
- un glvalue no volátil que se refiere a un objeto no volátil definido con constexpr, o que se refiere a un subobjeto no mutable de dicho objeto, o
- un valor no volátil de tipo literal que se refiere a un objeto no volátil cuya vida útil comenzó dentro de la evaluación de e
Esta regla también explica por qué el caso original no es una expresión constante, ya que no se aplica ninguna excepción.
Quizás gcc
está permitiendo esto:
int b[a || 1]{};
como una matriz de longitud variable como una extensión, aunque debería proporcionar una advertencia con -pedantic
. Aunque eso no explicaría el caso static_assert, podrían ser plegables constantes, pero no creo que la regla de si-si pudiera ser considerada una expresión constante.
Actualización, posible extensión gcc
A partir de este informe de error, el RHS de los operadores lógicos puede hacer que el LHS no sea evaluado en expresión constante, esto parece una posible extensión de gcc:
Esto se compila sin incidentes, a pesar de usar un objeto no constante en una expresión constante:
int i; static_assert( i || true, "" ); static_assert( ! ( i && false ), "" );
Parece estar asumiendo que || y && son conmutativos, pero el cortocircuito solo funciona en una dirección.
y el comentario final dice:
Creo que esta es una extensión de lenguaje útil, que podría usar un interruptor para deshabilitar. Sería bueno si static_assert fuera siempre estricto.
Esto parece una extensión no conforme que debería activar una advertencia cuando se usa el indicador -pedantic
similar en vano para emitir. ¿Es una extensión de compilador conforme para tratar las funciones de la biblioteca estándar no constexpr como constexpr? .
C ++ 11 / C ++ 14 Cita
La sección 5.20
es la sección 5.19
en C ++ 14 y C ++ 11, la cita relevante del borrador de la norma C ++ 14 es:
una conversión de lvalue a rvalue (4.1) a menos que se aplique a
un valor no volátil de tipo integral o enumeración que se refiere a un objeto const no volátil con una inicialización anterior, inicializado con una expresión constante [Nota: un literal de cadena (2.14.5) corresponde a una matriz de dichos objetos. —Endente final], o
un glvalue no volátil que se refiere a un objeto no volátil definido con constexpr, o que se refiere a un subobjeto no mutable de dicho objeto, o
un glvalue no volátil de tipo literal que se refiere a un objeto no volátil cuya vida comenzó en la evaluación de e;
y para el borrador de la norma C ++ 11 es:
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 glvalue de tipo literal que se refiere a un objeto no volátil definido con constexpr, o que se refiere a un subobjeto de dicho objeto, o
un glvalue de tipo literal que se refiere a un objeto temporal no volátil cuya duración no ha finalizado, inicializado con una expresión constante;