Static Constexpr vs Inline Constexpr in C++
Understanding the difference between static constexpr
and inline constexpr member variables in C++ primarily
depends on the C++ standard version being used. In modern C++ (C++17 and
later), any static constexpr member variable is implicitly
inline, making the two forms functionally identical for
member variables. However, historically and semantically, the
inline specifier addresses linkage and the One Definition
Rule (ODR), resolving limitations that previously required out-of-line
definitions for static constexpr members.
The Pre-C++17
Problem: ODR-Use of static constexpr
Prior to C++17, declaring a static constexpr variable
inside a class only served as an in-class declaration:
struct Config {
static constexpr int MaxRetries = 3; // Declaration with initializer
};While you could use Config::MaxRetries in compile-time
contexts (such as array bounds or template arguments), problems arose
when the variable was "ODR-used" (One Definition Rule used). An ODR-use
occurs when you take the variable's address or bind it to a non-inlined
reference:
void logValue(const int& val);
logValue(Config::MaxRetries); // ODR-use: causes undefined reference linker error in C++11/C++14To resolve this in C++11 and C++14, programmers were required to
provide an out-of-line definition in a single implementation file
(.cpp):
constexpr int Config::MaxRetries; // Out-of-line definitionThe C++17 Solution: Inline Variables
C++17 introduced the inline specifier for variables. An
inline variable can be defined in multiple translation
units (such as via a shared header file) without violating the One
Definition Rule, as the linker merges them into a single object.
Alongside this feature, the C++17 standard updated the rules for
static constexpr member variables: any
static constexpr member variable is now implicitly an
inline variable.
Because of this rule, the following declarations in C++17 and later are completely equivalent:
struct Config {
static constexpr int ValueA = 10; // Implicitly inline in C++17+
static inline constexpr int ValueB = 10; // Explicitly inline (redundant)
};In modern C++, both ValueA and ValueB can
have their addresses taken or be passed by reference from any
translation unit without needing a separate out-of-line definition in a
.cpp file.
Can Non-Static
Member Variables Be constexpr?
A non-static data member cannot be declared constexpr. A
constexpr variable must have a value that is constant and
known at compile time. Since non-static members are instantiated
per-object at runtime, declaring a non-static member variable as
constexpr or inline constexpr is a compilation
error.
What About Member Functions?
For member functions, the distinction is also resolved implicitly:
- Any function declared
constexpris automatically consideredinline. - Explicitly writing
inline constexpron a member function is valid, but theinlinekeyword is redundant.
Key Takeaways
- In C++11 and C++14:
static constexprdata members are notinline. If they are ODR-used (e.g., passed by const reference), an out-of-line definition in a separate.cppfile is required to avoid linker errors. - In C++17 and Later:
static constexprmember variables are implicitlyinline. Adding theinlinekeyword (static inline constexpr) is valid but redundant. - Non-Static Members: Non-static member variables can
never be
constexpr.