Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing constants: when to use static constexpr and inline constexpr?

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.

like image 234
jonspaceharper Avatar asked Jan 31 '19 17:01

jonspaceharper


People also ask

Does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?

Should I use const or constexpr?

const applies for variables, and prevents them from being modified in your code. constexpr tells the compiler that this expression results in a compile time constant value, so it can be used in places like array lengths, assigning to const variables, etc.

Do constexpr functions have to be inline?

Yes ([dcl. constexpr], §7.1. 5/2 in the C++11 standard): "constexpr functions and constexpr constructors are implicitly inline (7.1. 2)."

Is constexpr variable inline?

A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.


2 Answers

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.

like image 140
Acorn Avatar answered Oct 24 '22 04:10

Acorn


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.

like image 40
Barry Avatar answered Oct 24 '22 04:10

Barry