and c++ c++11 language-lawyer constexpr linkage

and - constexpr in c++



constexpr constantes globales en un archivo de encabezado y odr (1)

Desafortunadamente, estoy algo confundido acerca de constexpr , las constantes globales declaradas en los archivos de encabezado y la odr.

En resumen: ¿Podemos concluir desde aquí?

https://isocpp.org/files/papers/n4147.pdf

ese

constexpr MyClass const MyClassObj () { return MyClass {}; } constexpr char const * Hello () { return "Hello"; }

es preferible a

constexpr MyClass const kMyClassObj = MyClass {}; constexpr char const * kHello = "Hello";

para definir globales en un archivo de encabezado si quiero "usar" esas entidades declaradas / definidas globalmente y no quiero pensar en cómo las uso?


Nota: a partir de C ++ 17, puede declarar sus variables como en línea .

TL; DR : Si desea estar en el lado (muy) seguro, vaya con las funciones constexpr. Sin embargo, no es inherentemente necesario, y ciertamente no lo será si está realizando operaciones triviales en estos objetos y está únicamente interesado en su valor, o simplemente no los use en los escenarios peligrosos que se enumeran a continuación.

El problema fundamental es que las variables const en el ámbito del espacio de nombres como la suya (generalmente) tienen vínculos internos ( [basic.link]/(3.2) ). Esto implica que cada unidad de traducción que compile el encabezado correspondiente observará una entidad diferente (es decir, un símbolo).

Ahora imagine que tenemos una plantilla o función en línea en un encabezado usando esos objetos. La ODR es muy precisa sobre este escenario - [basic.def.odr]/6 :

"inicializado con una expresión constante" ciertamente se cumple, ya que estamos hablando de constexpr . Por lo tanto, "el objeto tiene el mismo valor en todas las definiciones de D " si no te importa.

"el objeto no se usa correctamente" es probablemente la única condición cuestionable. Básicamente, requiere que no se requiera la existencia de las variables en tiempo de ejecución como un símbolo, lo que a su vez implica que

  • No lo vinculas a una referencia (=> no lo reenvías!)

  • Usted no (ni explícitamente ni implícitamente) toma su dirección.

La única excepción a la segunda regla son las matrices, que pueden tomarse la dirección de forma implícita dentro de una operación de subíndice, siempre que las dos reglas anteriores no se violen para el glvalue producido.

Más precisamente, odr-use se rige por [basic.def.odr]/3 :

Una variable x cuyo nombre aparece como una expresión potencialmente evaluada ex es odr-used by ex menos que la aplicación de la conversión de valor de rvalor (4.1) a x produzca una expresión constante (5.20) que no invoque ninguna función no trivial y , si x es un objeto, ex es un elemento del conjunto de resultados potenciales de una expresión e , donde cualquiera de las conversiones de lvalor a valor (4.1) se aplica a e , o e es una expresión de valor descartado (Cláusula 5 ).

La aplicación de ltr a cualquier variable constexpr se comportará como lo requiere la primera parte. La segunda parte requiere que la variable se use como un valor en lugar de un objeto real; es decir, eventualmente se descarta o se evalúa directamente, dando las reglas básicas anteriores.

Si evita el uso de la variable dentro de las funciones en línea, plantillas o similares, está bien. Pero si usa el valor de retorno de una función constexpr correspondiente, no tendrá que preocuparse, ya que los valores predeterminados ya se están comportando más como valores / literales (no objetos) y las funciones constexpr están en línea y definitivamente no violarán la ODR (si no constexpr variables constexpr dentro de eso!).