Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In class nested static const member variable initialization Clang vs GCC which compiler is right?

Consider the following piece of code:

#include <iostream>

struct Foo {
  static int const i = i + 1;
};

int main() {
  std::cout << Foo::i << std::endl;
}

Clang version 3.7 compiles this and outputs 1.

Live Demo

While GCC version 5.3 emits an error:

error: 'i' was not declared in this scope

Live Demo

Q:

Which one of the two compilers conforms to the C++ standard?

like image 720
101010 Avatar asked Mar 04 '16 09:03

101010


2 Answers

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.

like image 177
Columbo Avatar answered Oct 16 '22 22:10

Columbo


A static const member initialized in-class must be initialized by a constant expression. In the initializer of i, i is not initialized by a constant expression (yet) and so is not a constant expression itself. In my view both compilers are guilty.

  • clang, for accepting the program
  • gcc, for giving a misleading error message
like image 2
n. 1.8e9-where's-my-share m. Avatar answered Oct 16 '22 21:10

n. 1.8e9-where's-my-share m.