I want a header file with a non-integral constant in it, e.g. a class. Note the constant does not need to be a compile-time constant.
static const std::string Ten = "10";
This compiles but is undesirable as each compilation unit now has its own copy of Ten.
const std::string Ten = "10";
This will compile but will fail with a linker error for multiply defined Ten.
constexpr std::string Ten = "10"s;
This would work but only if the strings constructor was constexpr as well. It will be but I can't count on every non-integral constant to have a constexpr constructor ... or can I?
extern const std::string Ten = "10";
This seems to work but I'm afraid I'll get a linker error if I breath on it wrong.
inline const std::string Ten( ) { return "10"; }
This has everything I want except a clean syntax. Plus now I have to refer the constant as a function call, Ten()
.
inline const std::string = "10";
This seems to be the ideal solution. Of course inline
variables aren't allowed by the standard.
You seem to have them mixed up.
You are right about
static const std::string Ten = "10";
version. It will "work", but it will create a separate object in each translation unit.
The version without static
will have the same effect. It won't produce linker errors, but will define a separate object in each translation unit. In C++ language const
objects have internal linkage by default, meaning that
const std::string Ten = "10"; // `static` is optional
is exactly equivalent to the previous version with static
.
The version with extern
and initializer
extern const std::string Ten = "10"; // it's a definition!
will produce a definition of an object with external linkage (it is a definition because of the presence of an initializer). This version will result in linker errors, since you'll end up with multiple definitions of an object with external linkage - a violation of ODR.
In order to achieve what you are trying to achieve, you have to declare your constant in the header file
extern const std::string Ten; // non-defining declaration
and then define it (with initializer) in one and only one of the implementation files
extern const std::string Ten = "10"; // definition, `extern` optional
(If the constant is pre-declared as extern
, then extern
in the definition is optional. Even without an explicit extern
it will define a const object with external linkage.)
I don't know if there's a better way in C++ but the best way in C (which will also work in C++) is one of the ones you've listed.
Have a separate compilation unit (eg,ten.cpp
) holding just the data:
const std::string Ten = "10";
and a header file (eg,ten.h
) declaring it so it can be used elsewhere:
extern const std::string Ten;
Then you just have to ensure any compilation unit that wants to use it include the header file (eg,ten.h
), and any executable that wants to use it link with the separate compilation unit (eg,ten.o
).
This gives you one copy of the variable, accessible anywhere. Of course, you could just define it in the header file as static and have one copy per compilation unit. That would simplify what files you need to have and the static would ensure there's no doubly-defined symbols. But that's not something I'd ever recommend.
I don't know why you state:
but I'm afraid I'll get a linker error if I breath on it wrong
This is accepted practice from long ago and you should know how all these things fit together if you wish to call yourself a C++ programmer (no insult intended).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With