GCC is of course wrong to complain about the name being undeclared, since the point of declaration of i
is immediately after its declarator.
However, GCC is arguably right in rejecting the snippet overall. [class.static.data]/3:
If a non-volatile const
static data member is of integral or
enumeration type, its declaration in the class definition can specify
a brace-or-equal-initializer in which every initializer-clause
that is an assignment- expression is a constant expression (5.20).
And for [expr.const]/(2.7) not to fail, one of its four sub bullets must apply:
an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile
const
object with a preceding
initialization, initialized with a constant expression, or
- a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
- a non-volatile glvalue that refers to a non-volatile object defined with
constexpr
, or that refers to a non-mutable sub-object of such an
object, or
- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of
e
;
(2.7.1) is the only plausible candidate, but since i
has not previously been initialized using an initializer, it doesn't apply.
Note that Clang is completely consistent:
constexpr int i = i;
void f() {
// constexpr int j = j; // error
static constexpr int h = h;
}
It appears that it treats i
as "properly" initialized in its initializer if it has static storage duration. I filed bug #26858.
static int const i = i + 1;
makes little sense, if you want to initialize at 1, just initialize at 1. – Shark=
. Don't know if there are any special rules for const static members. But of course it is UB to read the value in the initializer. – Bo Persson