Dirección única para la variable constexpr

¿Es posible tener una dirección única asignada para una variable constexpr, es decir, la misma para todas las unidades de traducción donde la variable está disponible (generalmente a través de un encabezado)? Considere el siguiente ejemplo:

// foo.hh #include  constexpr int foo = 42; // a.cc #include "foo.hh" void a(void) { std::cout << "a: " << &foo << std::endl; } // b.cc #include "foo.hh" extern void a(void); int main(int argc, char** argv) { a(); std::cout << "b: " << &foo << std::endl; } 

Comstackndo a.cc y b.cc separado, y uniéndolos entre sí usando gcc 4.7, veo dos direcciones impresas diferentes. Si agrego la palabra clave extern en el encabezado, obtengo un error de vinculador duplicate symbol _foo in: ao and bo cual me parece sorprendente, porque pensé que agregar extern probablemente causaría que el comstackdor importe ese símbolo desde otro objeto de exportarlo desde el objeto actual. Pero parece que mi comprensión de cómo funcionan las cosas estaba mal aquí.

¿Hay una manera razonable de tener un constexpr declarado en un encabezado, de modo que todas las unidades de traducción puedan usarlo en sus expresiones constantes, y de tal manera que todas las unidades de traducción estén de acuerdo con la dirección de ese símbolo? Espero que algún código adicional denote la unidad de traducción única a la que realmente pertenece este símbolo, al igual que con las variables extern y no extern sin constexpr .

Si necesita tomar la dirección de la variable constexpr, declararla como una variable miembro estática. Puede usarse como una expresión constante de esta manera (en lugar de usar una función que devuelve una constante).

foo.hpp:

 #ifndef FOO_HPP #define FOO_HPP struct Foo { static constexpr int foo { 42 }; // declaration }; #endif // FOO_HPP 

foo.cpp:

 #include "foo.hpp" constexpr int Foo::foo; // definition 

bar.cpp:

 #include "foo.hpp" const int* foo_addr() { return &Foo::foo; } int foo_val() { return Foo::foo; } 

main.cpp:

 #include  #include "foo.hpp" extern const int* foo_addr(); extern int foo_val(); constexpr int arr[Foo::foo] {}; // foo used as constant expression int main() { std::cout << foo_addr() << " = " << foo_val() << std::endl; std::cout << &Foo::foo << " = " << Foo::foo << std::endl; } 

Salida:

 $ g++ -std=c++11 foo.cpp bar.cpp main.cpp -o test && ./test 0x400a44 = 42 0x400a44 = 42 

Creo que constexpr es más para funciones cuyo valor de retorno es constante. Puede vincular una variable constante al valor de retorno de una función constexpr y exponer eso externamente. Por ejemplo:

 // constexpr.h #ifndef __CONSTEXPR_H #define __CONSTEXPR_H extern const int foo; #endif // __CONSTEXPR_H // constexpr.cpp #include "constexpr.h" constexpr int foo_expr() { return 42; } const int foo = foo_expr(); // unit1.cpp #include  #include "constexpr.h" void unit1_print_foo() { std::cout << &foo << " = " << foo << std::endl; } // unit2.cpp #include  #include "constexpr.h" void unit2_print_foo() { std::cout << &foo << " = " << foo << std::endl; } // main.cpp extern void unit1_print_foo(); extern void unit2_print_foo(); int main(int, char**) { unit1_print_foo(); unit2_print_foo(); } 

Mi resultado es:

 $ g++-4.7 -std=c++11 constexpr.cpp unit1.cpp unit2.cpp main.cpp -o test && ./test 0x400ae4 = 42 0x400ae4 = 42 

Sin embargo, normalmente debería ser suficiente para hacer que la función foo_expr sea ​​visible externamente, y las personas que llaman usarían foo_expr() para obtener el valor en lugar de tratarlo como una variable.