The following code:
struct S {
static constexpr int rolling_sum[4]{
0,
rolling_sum[0] + 1,
rolling_sum[1] + 2,
rolling_sum[2] + 3
};
};
is accepted by clang (tested with version 12), but rejected by gcc (tested with version 11) with the following errors:
test.cpp:4:9: error: ‘rolling_sum’ was not declared in this scope
4 | rolling_sum[0] + 1,
| ^~~~~~~~~~~
test.cpp:5:9: error: ‘rolling_sum’ was not declared in this scope
5 | rolling_sum[1] + 2,
| ^~~~~~~~~~~
test.cpp:6:9: error: ‘rolling_sum’ was not declared in this scope
6 | rolling_sum[2] + 3
| ^~~~~~~~~~~
Is this code valid C++?
My guess is that it should be valid because [basic.scope.pdecl] p1 states that the point of declaration of a variable is just before its initializer, meaning the variable should be in scope in its initializer; but I'm not sure if I'm overlooking something else that could be relevant here.
constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.
The alternatives don't have the all of the positives of static constexpr - you're guaranteed compile time processing, type safety, and (potentially) lower usage of memory (constexpr variables don't need to take up memory, they are effectively hard coded unless if possible).
A constexpr (or indeed, any kind of variable) need not be stored anywhere if its address is never taken. A constexpr in global or namespace ,when I address it,it should store in .
A static member variable (but not a namespace-scope variable) declared constexpr is implicitly an inline variable.
You aren't missing anything. This is GCC bug 99059, reported in GCC 11.
Your case applies too, since just like static inline
, a constexpr
variable must be initialized at the point of declaration. The same lookup related bug would affect C++14 code as well.
As your cited [basic.scope.pdecl]/1 allows (as none of /3 and forward rejects it), your program is well-formed.
We may study a similar example for which GCC confusingly rejects parts of:
struct S {
static constexpr int x{42};
static constexpr int y[2]{
S::x, // #1 GCC: OK
S::y[0] + 1 // #2 GCC: error: incomplete type 'S' used in nested name specifier
};
};
with an error message at #2 that should arguably (were it not a rejects-invalid) be applied to #1.
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