In the answers to this question, (static constexpr vs constexpr in function body?), it is stated that static constexpr
puts the variable in the .rodata
section, whereas constexpr
alone may allow initialising the variable at run-time.
IMPORTANT: This questions is about static variables within a function, not to do with linking external libraries.
My question is: in what situation would we prefer one of these two to the other in the code, in practice? Can one be better than the other for some codes? It is very hard to imagine how this can happen. After all, with either options, we can write codes in exactly the same way, with the same computational result. And the compiler can presumably optimise to make the better choice. So what does the programmer need to judge when choosing?
If you don't use a constexpr
variable as an lvalue (i.e., you only read its value but don't use its address) then its storage duration doesn't matter. The static constexpr
variable and automatic constexpr
variable are not odr-used (only their value is used), and will be optimized out. For instance, with GCC:
int f(bool b) {
int unused = 999; // At -O1, this is optimized out
constexpr int x = 123; // At -O1, this is optimized out
static constexpr int y = 456; // At -O0, this is optimized out
if (b) {
return x; // Replaced with "return 123;" at -O0 (x not actually used)
} else {
return y; // Replaced with "return 456;" at -O0
}
}
However, there is a difference when used as an lvalue. It can make your code wrong:
const char* name(bool b) {
static constexpr char name[2][6] = { "false", "true\0" };
return name[b]; // Would be dangling if name was not `static`
}
Or it can have performance impacts:
unsigned permute(unsigned i) {
[[assume(i < 10)]];
constexpr int table[10] = { 4, 5, 8, 2, 3, 1, 9, 6, 0, 7 };
return table[i];
}
Since table
was not declared static, it will copy the initializer onto the stack and then index the stack. The initializer will be stored in the .rodata section. If table
was static, return table[i];
would just index into something in the .rodata section.
It looks like clang is smart enough to optimize this specific case (GCC isn't), but there will be differences if you want to pass a large constant block to a void unknown_external_function(const void*);
(the compiler will be forced to copy onto the stack if the constexpr
variable isn't static
).
It's hard to think of a situation where you would want to use an automatic constexpr
variable over a static constexpr
variable, other than pre-C++23 where constexpr
functions can't declare static constexpr
variables.