In C++17 we got inline variables and I have assumed that global constexpr variables are implicitly inline. But apparently this is true only for static member variables.
What is the logic/technical limitation behind this?
source:
A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.
A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.
constexpr is a compile time feature, where inline/static are runtime features. The meaning of constexpr is more restricted than static. The meaning is that given a particular input value the return value is always the same, and the copiler ought to be able to work it out completely during compilation.
Yes ([dcl. constexpr], §7.1. 5/2 in the C++11 standard): "constexpr functions and constexpr constructors are implicitly inline (7.1. 2)."
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.
The point here is that constexpr int x = 1;
at namespace scope has internal linkage in C++14.
If you make it implicitly inline without changing the internal linkage part, the change would have no effect, because the internal linkage means that it can't be defined in other translation units anyway. And it harms teachability, because we want things like inline constexpr int x = 1;
to get external linkage by default (the whole point of inline, after all, is to permit the same variable to be defined in multiple translation units).
If you make it implicitly inline with external linkage, then you break existing code:
// TU1
constexpr int x = 1;
// TU2
constexpr int x = 2;
This perfectly valid C++14 would become an ODR violation.
The reason why constexpr
static data members were made implicitly inline
was to solve a common problem in C++: when defining a class-scoped constant, one was previously forced to emit the definition in exactly one translation unit, lest the variable be ODR-used:
// foo.h
struct foo {
static constexpr int kAnswer = 42;
};
// foo.cpp
// a linker error will occur if this definition is omitted before C++17
#include "foo.h"
constexpr int foo::kAnswer;
// main.cpp
#include "foo.h"
#include <vector>
int main() {
std::vector<int> bar;
bar.push_back(foo::kAnswer); // ODR-use of 42
}
In such cases, we usually care only about the value of the constant, not its address; and it's convenient for the compiler to synthesize a unique location for the constant in case it really is ODR-used, but we don't care where that location is.
Thus, C++17 changed the rules so that the out-of-line definition is no longer required. In order to do so, it makes the declaration of foo::kAnswer
an inline definition, so that it can appear in multiple translation units without clashing, just like inline functions.
For namespace-scope constexpr
variables (which are implicitly static
, and therefore have internal linkage, unless declared extern
) there is no similar issue. Each translation unit has its own copy. inline
, as it's currently specified, would have no effect on such variables. And changing the existing behaviour would break existing programs.
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