This question is a followup question to C++17: still using enums as constants?.
Legacy constants come in several forms, notably:
#define CONSTANT
In C++17, the proper way to replace those old idioms (e.g. #define
) in headers in namespace scope is to use constexpr inline
variables -- and not static
(which is implied: they already have internal linkage).
While typically you won't encounter ODR issues (because integer compile-time constants such as those you describe are rarely ODR-used and there is a provision for their typical usage within inline
functions), it is best to mark them as inline
now that we have the feature in the language and avoid all problems.
See Should `const` and `constexpr` variables in headers be `inline` to prevent ODR violations? for the technical details about it.
Your go-to for global constants in C++17 should just be:
inline constexpr int CONSTANT = 42;
This gets you a nice, first-class variable that you can use in constant expressions and that won't have ODR-issues. You can take references to it.
Macros bring in the problem of... being macros. Enums are limited to integral types. With constexpr
variables, you can have them of any literal type. In C++20, you'll very likely be able to just go wild and write:
inline constexpr std::vector<int> small_primes = {2, 3, 5, 7, 11};
inline constexpr std::string cool_name = "Barry";
It is the only option that allows this.