2012-04-29 12 views
22

Estoy tratando de declarar un puntero constexpr inicializado a un valor constante entera, pero sonido metálico está frustrando todos mis intentos:constexpr valor del puntero

Intento 1:

constexpr int* x = reinterpret_cast<int*>(0xFF); 

test.cpp:1:20: note: reinterpret_cast is not allowed in a constant expression 

Intento 2:

constexpr int* x = (int*)0xFF; 

test.cpp:1:20: note: cast which performs the conversions of a reinterpret_cast is not allowed in a constant expression 

Intento 3:

constexpr int* x = (int*)0 + 0xFF; 

test.cpp:1:28: note: cannot perform pointer arithmetic on null pointer 

¿Lo que trato de hacer no está permitido por diseño? Si es así, ¿por qué? Si no, ¿cómo puedo hacerlo?

Nota: gcc acepta todo esto.

+2

¿Por qué necesita un constexpr aquí? ¿No es exactamente igual que const si no está utilizando una función? –

+0

@RobertMason: Bueno, por ejemplo, si es un miembro estático de una clase, y no es constexpr, no puedo inicializarlo en línea. – HighCommander4

+1

Tal vez una función de miembro en línea estática sería más apropiada que un miembro de datos. –

Respuesta

18

Como observa Luc Danton, las reglas en [expr.const]/2 bloquean los intentos y dicen que no se permiten varias expresiones en constante de núcleo expresiones, entre ellos:

- un reinterpret_cast
- una operación que tendría un comportamiento indefinido [nota: en particular, [...] cierta aritmética de puntero [...] - nota final]

El La primera viñeta descarta su primer ejemplo. El segundo ejemplo se descarta por la primera bala anterior, además de la regla de [expr.cast]/4 que:

Las conversiones realizadas por [...] un reinterpret_cast [...] se puede realizar utilizando la notación de conversión explícita de tipo. Se aplican las mismas restricciones y comportamientos semánticos.

La segunda bala se añadió por WG21 core issue 1313, y aclara que la aritmética de punteros en un puntero nulo no está permitida en una expresión constante. Esto descarta su tercer ejemplo.

Incluso si estas restricciones no se aplican a las expresiones constantes fundamentales, que todavía no sería posible inicializar un puntero constexpr con un valor producido por emitan un número entero, ya que una variable puntero constexpr debe ser inicializado por una expresión constante dirección, que, por [expr.const]/3, debe evaluar a

la dirección de un objeto con duración de almacenamiento estático, la dirección de una función o un valor de puntero nulo.

Un entero de tipo puntero no es ninguno de estos.

g ++ aún no hace cumplir estrictamente estas reglas, pero sus lanzamientos recientes se han estado acercando a ellos, por lo que deberíamos suponer que finalmente los implementará completamente.

Si su objetivo es declarar una variable para la cual se realiza la inicialización estática, simplemente puede soltar el constexpr - tanto clang como g ++ emitirán un inicializador estático para esta expresión. Si necesita esta expresión para ser parte de una expresión constante, por alguna razón, usted tiene dos opciones:

  • reestructurar su código para que un intptr_t se pasa alrededor en lugar de un puntero, y echarlo a un tipo de puntero cuando se necesita (fuera de una expresión constante) o
  • Use __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF. Esta forma exacta de expresión (con __builtin_constant_p en el lado izquierdo de un operador condicional) deshabilita la comprobación estricta de la expresión constante en los brazos del operador condicional, y es una extensión de GNU no portátil poco conocida, pero documented compatible con tanto gcc como clang.
4

La razón es la dada por el mensaje de error (por una vez, muy útil): reinterpret_cast no está permitido en una expresión constante. Se enumera como una de la excepción explícita en 5.19 (párrafo 2).

Cambiar el reinterpret_cast en un molde de estilo C todavía termina con el equivalente semántico de reinterpret_cast, por lo que no ayuda (y de nuevo el mensaje es muy explícito).

Si tiene una manera de obtener un puntero con el valor 0, puede usar p + 0xff, pero no puedo pensar en una forma de obtener dicho puntero con una expresión constante. Podría haber dependido del valor del puntero nulo (0 en un contexto de puntero como lo hizo, o nullptr) teniendo un valor de 0 en su implementación, pero como usted mismo ha visto, su implementación se niega a hacerlo. Creo que está permitido hacer eso. (Por ejemplo, las implementaciones pueden rescatar para la mayoría de las expresiones constantes.)

+1

y debe ser '0xff/sizeof (* x)' que él agrega. –

Cuestiones relacionadas