15

This question is a followup question to C++17: still using enums as constants?.

Legacy constants come in several forms, notably:

  • #define CONSTANT x
  • enum { CONSTANT = x };
  • const /*int/unsigned/whatever*/ CONSTANT = x;

A comment about static constexpr and inline constexpr constants as a replacement got me thinking on the subject of updating our many, many legacy constants (particularly #define constants).

As I understand, an inline constexpr value is basically just substituted in place, like an inlined function (which I've been shown to be wrong about). Conversely, a static constexpr value is stored as part of the binary in a separate area. Assuming I understand correctly, when should one be preferred over the other? My hunch is that, for integral constants, inline constexpr will generally be preferred.

5
  • Are inline constexpr suitable for header files? Also the constexpr int* z = nullptr; is more akin to int* const z = nullptr;, which may be a surprise if a person expected it to be like int const* z = nullptr;. Commented Jan 31, 2019 at 18:03
  • As I understand, an inline constexpr value is basically just substituted in place, like an inlined function You have how inline works wrong. inline does not mean substitute the thing in the call site (although it does act as a suggestion). inline is used for ODR purposes. see: en.cppreference.com/w/cpp/language/inline Commented Jan 31, 2019 at 18:15
  • Sorry for the confusion, I realize that constexpr is automatically inline. I was quoting the comment that got this started. I've updated the question to reflect that I'm really asking about constexpr vs static constexpr values, typically integral ones. Commented Jan 31, 2019 at 18:20
  • 1
    @Eljay They are not only suitable, they are required if you want to avoid ODR issues. See stackoverflow.com/q/53794625/9305398 Commented Jan 31, 2019 at 18:22
  • 1
    @MatthieuBrucher No, constexpr does not imply inline. Commented Jan 31, 2019 at 18:23

2 Answers 2

16

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.

Sign up to request clarification or add additional context in comments.

1 Comment

std::string cool_name = "Barry" Ha! I see what you did there :)
11

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.

2 Comments

Since exapnded #defines end up as "pure" source code, they are essentially text, while inline variables are proper variables (for example, you can take the address of them). I'd love to know what the standard says about code generation. In simple examples, the same assembly for both is produced, but are there any guarantees for that?
"... use constexpr inline variables -- and not static (which is implied: they already have internal linkage)." Just to clarify a little bit on this: Variables marked with const and constexpr have internal linkage, so marking them as static won't change that. However, marking them with inline instead will give them external linkage, which provides an exception to the ODR-rule and allows the objects to eventually be merged as a single entity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.