usuario4637702
El siguiente fragmento funciona bien en Clang 3.5 pero no en GCC 4.9.2:
int main()
{
constexpr volatile int i = 5;
}
con error:
error: tanto ‘volátil’ como ‘constexpr’ no se pueden usar aquí
Si inspecciono el ensamblaje que genera Clang, muestra 5
como se esperaba:
movl $5, -4(%rsp)
En el CCG, constexpr int i = 5
está optimizado, pero volatile int i = 5
también muestra 5
en la asamblea volatile const int i = 5
compila en ambos compiladores. No es un concepto extraño que algo sea volátil y constante al mismo tiempo.
¿Qué compilador es correcto según los estándares?
Shafik Yaghmour
Sí, esto es válido, hubo informe de defectos 1688: Variables constexpr volátiles que se archivó para esto, diciendo:
No parece haber lenguaje en la redacción actual que indique que constexpr no se puede aplicar a una variable de tipo calificado como volátil. Además, la redacción en 5.19 [expr.const] el párrafo 2 que hace referencia a “un objeto no volátil definido con constexpr” podría inducir a inferir que la combinación está permitida pero que tal variable no puede aparecer en una expresión constante. ¿Cuál es la intención?
fue rechazado como no un defecto (NAD), la respuesta y justificación fue:
La combinación se permite intencionalmente y podría usarse en algunas circunstancias para forzar la inicialización constante.
Como señala el DR, dicha variable en sí misma no se puede utilizar en un expresión constante:
constexpr volatile int i = 5;
constexpr int y = i ; // Not valid since i is volatile
Sección [expr.const]/2 incluye todos los casos que hacen que una expresión condicional no sea una expresión constante central, incluidos:
una conversión de lvalue a rvalue (4.1) a menos que se aplique a
y todas las excepciones requieren:
[…]que se refiere a un no volátil […] objeto […]
-
yo supo tenía que haber un DR, pero no pudo encontrar uno. Bien hecho.
– Casey
5 de marzo de 2015 a las 18:42
Casey
Citando N4140 [dcl.constexpr]/9:
A
constexpr
especificador utilizado en una declaración de objeto declara el objeto comoconst
. Dicho objeto tendrá un tipo literal y se inicializará.
El tipo literal se define en [basic.types]/10:
Un tipo es un tipo literal si es:
(10.1) —
void
; o(10.2) — un tipo escalar; o
(10.3) — un tipo de referencia; o
(10.4) — una matriz de tipo literal; o
(10.5) — un tipo de clase (Cláusula 9) que tiene todas las siguientes propiedades:
(10.5.1) — tiene un destructor trivial,
(10.5.2) — es un tipo agregado (8.5.1) o tiene al menos una
constexpr
constructor o plantilla de constructor que no es un constructor de copia o movimiento, y(10.5.3) — todos sus miembros de datos no estáticos y clases base son de tipos literales no volátiles.
El tipo escalar está en el párrafo 9:
Tipos aritméticos (3.9.1), tipos de enumeración, tipos de puntero, tipos de puntero a miembro (3.9.2),
std::nullptr_t
y las versiones calificadas cv de estos tipos (3.9.3) se denominan colectivamente tipos escalares.
int
es aritmética, entonces volatile int
es un tipo escalar y por lo tanto un tipo literal. constexpr volatile int i = 5;
es por lo tanto una declaración bien formada.
Curiosamente, una expresión que evalúa i
no puede ser un expresión-constante-núcleo ya que aplica una conversión de lvalue a rvalue a un glvalue de tipo volátil ([expr.const]/2). En consecuencia, las expresiones que evalúan i
no son ninguno expresiones constantes integrales ni expresiones constantes. no estoy seguro de que el constexpr
en esa declaración tiene algún efecto más allá de hacer i
implícitamente const
y (guiño a @TC) requiriendo que su inicializador sea una expresión constante.
He informado esto como GCC error 65327veremos qué tiene que decir la gente de GCC.
Actualización del 16 de marzo de 2015: se ha corregido un error para GCC 5.
-
La presencia de “no volátil” en (10.5.3) me dice que es al menos algo probable que el estándar pretendiera excluir los tipos calificados como volátiles en general, y permitir esto fue un descuido.
– usuario1084944
5 de marzo de 2015 a las 17:57
-
“No estoy seguro de que constexpr en esa declaración tenga algún efecto más allá de hacer i implícitamente const”. – Todavía restringe el inicializador para que sea una expresión constante.
– CT
5 de marzo de 2015 a las 17:57
-
Por lo que vale, aquí está el parche que introdujo este error. La prueba en wandbox muestra que el error se introdujo entre 4.5.4 y 4.6.4.
– usuario4637702
5 de marzo de 2015 a las 18:18
-
@TC de hecho, esta es la razón que utilizó el comité en el informe de defectos que menciono en mi respuesta. Sabía que tenía que haber un informe de defectos para esto.
– Shafik Yaghmour
5 de marzo de 2015 a las 18:36
-
@ user4637702 Ese cambio fue para permitir
const
Juntos conconstexpr
. Revisión 166013 introdujo los diversosconstexpr
comprobaciones, incluido el error cuandoconstexpr
yvolatile
se usan juntos.– Casey
5 de marzo de 2015 a las 18:40
constexpr
yconst
no son lo mismo– BЈовић
5 de marzo de 2015 a las 17:13
@TheBuzzSaw:
volatile
no significa que nada tenga tendencia a cambiar. simplemente significa que el acceso a la memoria puede tener efectos secundarios y, por lo tanto, el compilador debe tratarlo como E/S. Puede muy bien ser necesario usarvolatile
en un sistema incluso cuando se garantiza que el valor permanecerá constante.– usuario541686
5 de marzo de 2015 a las 17:14
@ user4637702 Sí, pero de otra manera no es cierto. Por ejemplo, intente crear un
constexpr std::string
objeto.– BЈовић
5 de marzo de 2015 a las 17:21
@TheBuzzSaw tal uso de un booleano como lo describe es un comportamiento indefinido.
– usuario541686
5 de marzo de 2015 a las 17:45
@TheBuzzSaw Por ejemplo,
const volatile
podría tener sentido para un mapa de memoria de solo lectura de un archivo que otro proceso está modificando simultáneamente, o registros mapeados en memoria de solo lectura de un dispositivo de hardware.– Casey
5 de marzo de 2015 a las 17:59