// Processor.cpp
#include "Constants.h"
// ... more code
and
// Editor.cpp
#include "Constants.h"
// ... more code
Doubts:
Is this safe regarding the “static initialization order fiasco”?
Obviously, I need it to be so.
The translation units that are created by the compilation of Processor.cpp and Editor.cpp, do they both contain their own copy of all the constant Strings, or are those constants only instantianted once and shared in the final linked product?
I’d like the “one copy shared by all translation units” more, as it feels like a waste of resources to have all those constants (they will become a lot) to be duplicated in each translation unit.
Is there a more idiomatic / ideal way to do this, perhaps via constexpr usage?
This is safe regarding static initialisation order. You are guaranteed that static data in each translation unit (TU) is initialised in the order it is declared, so because your constants are defined before the code that depends on them, you should be fine.
Every TU that includes this header will get its own copy of these constants, because const variables implicitly have internal linkage. The strings are pretty small though, so it’s probably nothing to worry about.
This gives the constants external linkage, and hints to the linker that it should only keep one copy of each object, should it find the same object defined in multiple TUs.
One more question: If the compiler (or better, the linker) decides to honour the inline keyword and only keep one of copy of the constant that would otherwise appear in multiple TUs, is the static initialisation of that single copy still guaranteed to happen before any usage in any linked TU?
In other words: does point #1 of your answer still holds even in the case of inline variables at namespace scope?
Dynamic initialization of a non-local variable with static storage duration… is partially-ordered if the variable is an inline variable that is not an implicitly or explicitly instantiated specialization
If V has partially-ordered initialization, W does not have unordered initialization, and V is defined before W in every translation unit in which W is defined, then… [omitting some stuff about threads] the initialization of V is sequenced before the initialization of W.