que compile c++ pointers c++11 clang constexpr

c++ - compile - llvm 3.7 0



Valor del puntero Constexpr (2)

Intento declarar un puntero constexpr inicializado a un valor entero constante, pero clang frustra todos mis intentos:

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.


Como señala Luc Danton, tus intentos están bloqueados por las reglas en [expr.const] / 2 que dicen que no se permiten varias expresiones en las expresiones constantes centrales , que incluyen:

- una reinterpret_cast
- una operación que tendría un comportamiento indefinido [Nota: incluida [...] cierta aritmética del puntero [...] - nota final]

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

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

La segunda viñeta fue agregada por WG21 núcleo problema 1313 , y aclara que la aritmética de puntero en un puntero nulo no está permitida en una expresión constante. Esto descarta su tercer ejemplo.

Incluso si estas restricciones no se aplicaran a expresiones constantes centrales, aún no sería posible inicializar un puntero constexpr con un valor producido al convertir un entero, ya que una variable apuntadora constexpr debe ser inicializada por una expresión constante de 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 elenco entero para el tipo de 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 eventualmente 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 que esta expresión forme parte de una expresión constante por algún motivo, tiene dos opciones:

  • Reestructurar su código para que se pase un intptr_t en lugar de un puntero y convertirlo en un tipo de puntero cuando lo necesite (fuera de una expresión constante) o
  • Use __builtin_constant_p((int*)0xFF) ? (int*)0xFF : (int*)0xFF __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.

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 aún termina con el equivalente semántico de reinterpret_cast , por lo que no ayuda (y de nuevo el mensaje es muy explícito).

Si tuviera una forma de obtener un puntero con valor 0 , podría usar p + 0xff pero no puedo pensar en una forma de obtener dicho puntero con una expresión constante. Podría haber confiado en el valor del puntero nulo ( 0 en un contexto de puntero como lo hizo, o nullptr ) que tiene 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).