constexpr static data member without initializer

constexpr' needed for in-class initialization of static data member
initialize static member c
static constexpr
in-class initialization of static data member of non-literal type
c++ static member object initialization
const vs constexpr
constexpr const
constexpr variable must be initialized by a constant expression
#include <complex>

struct S
{
  static std::complex<double> constexpr c;
};

gcc generates an error because an initializer is missing. Clang and MSVC do not generate an error.

As far as I know a constexpr static data member must have an initializer, even if it is of class type that has a constructor that can be called without arguments (as in this case). Unfortunately I don't have the latest C++ standard to back up my assumption.

So the correct code should initialize with a constructor, for instance:

struct S
{
  static std::complex<double> constexpr c {};
};

Can anyone prove which compiler is right and which is wrong?

GCC is wrong.

GCC uses the C++14 rules for constexpr variables, which requires an initializer to be provided. This is changed per P0386 (bold text is newly added text):

In 9.2.3.2p3, change:

If a non­-volatile n​on-­inline ​const static data member is of integral or enumeration type, its declaration in the class definition can specify a b​race­-or-­equal-­initializer​ in which every initializer-­clause​ that is an ​assignment-­expression​ is a constant expression (5.20). A​ static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace­-or-­equal-initializer in which every initializer-­clause that is an assignment­-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. — end note ]​ The member shall still be defined in a namespace scope if it is odr-­used (3.2) in the program and the namespace scope definition shall not contain an initializer.​ A​n inline static data member can be defined in the class definition and may specify a b​race­-or-­equal­-initializer.​ If the member is declared with the constexpr specifier, it may be redeclared in namespace scope with no initializer (this usage is deprecated; see D.X). Declarations of other static data members shall not specify a b​race­-or-­equal-initializer.​

constexpr static data member without initializer, GCC is wrong. GCC uses the C++14 rules for constexpr variables, which requires an initializer to be provided. This is changed per P0386 (bold  constexpr on types is indeed a restriction; one could imagine constexpr data members requiring initialization with a constant expression. Maybe, the benefits are too small or the original intention of constexpr violated for non-static data members. – dyp Dec 10 '14 at 20:10

constexpr static data member without initializer, The compiler does not generate an error although an initializer is missing. As far as I know a constexpr static data member must have an  Multiple initializations of inline static data member in Debug mode 1 Solution MSVC 15.7.3 generates false positive warning C26462 (mark it as a pointer to const) for a catch by pointer 1 Solution VCXProj DependentUpon Does not group files in Solution Explorer 1 Solution

From dcl.constexpr#1:

A function or static data member declared with the constexpr specifier is implicitly an inline function or variable

constexpr static data members are implicitly inline.

Also from class#static.data-3, emphasis mine:

inline static data member may be defined in the class definition and may specify a brace-or-equal-initializer.

Thus, GCC is wrong. brace-or-equal-initializer is not strictly required.

Reference: N4659 C++17 Draft

Static data members (C++ only), The declaration of a static data member in the member list of a class is not a definition. The initializer for a static data member is in the scope of the class declaring the struct Constants { static constexpr int bounds[] = { 42, 56 }; }; float​  This has something to do with the template parameter: It works as expected if the type of the static data member is not dependent on the template parameter, like static constexpr auto value = int{}; – dyp Mar 4 '15 at 20:30

The constexpr specifier (C++11), of a function or function template; The declaration of a static data member If you declare a function that is not a constructor with a constexpr specifier, that  If a static data member is declared constexpr, it is implicitly inline and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated. (since C++17)

constexpr static data member without initializer (part 2), constexpr static data member without initializer (part 2) Error C2737 'public: static std::complex<double> const S::c': 'constexpr' object must be initialized. This isn't possible, because unfortunately the Standard precludes initializing a static constexpr data member in any context where the class is complete. The special rule for brace-or-equal-initializers in 9.2p2 only applies to non-static data members, but this one is static.

[class.static.data], A static data member is not part of the subobjects of a class. in namespace scope with no initializer (this usage is deprecated; see [depr.static.constexpr]). An aggregate type in C++11 could not be initialized as an aggregate if it contained any members that had default member initializers. In C++14 the committee removed this restriction on non-static data members having default member initializers.

Comments
  • I think you are right. Clang 6.0.0 does not report an error in C++17 mode, but it does in C++14 mode and complains about a missing initializer for a constexpr static data member. So the rule seems to have changed from C++14 to C++17 (just as you have explained). gcc is wrong, and clang and MSVC (hard to believe) are right. Thanks for your explanation.
  • Actually it depends on the standard. The OP didn't specify a particular version of C++, therefore gcc isn't neccessarily wrong - it depends on the language version (and compiler perhaps - maybe they fixed it in the meanwhile? I don't have the latest gcc version installed).
  • is c a literal? if not, then that doesn't apply.
  • For specialization of double, std::complex is.
  • @codekaizer Wrong paragraph. You want this.
  • @andreee You are right for C++11/14. But in C++17 the rule has changed (see the answer from xskxzr). In C++11/14 mode clang generates an error, too.
  • @xy: Thanks for noting, updated! Please note that you didn't specify a specific language version, so there are two different answers (as you pointed out).
  • is there a GCC bug for this? Any details of "may specify". To me, "may specify" means that it may not, case in which the constexpr no-arg c-tor for that literal type does its job. But this doesn't work and GCC mandates an initialiser