#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?

Some programmer dude's user avatar

asked Jun 1, 2018 at 7:17

x y's user avatar

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.​

answered Jun 1, 2018 at 9:02

xskxzr's user avatar

3 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.

2018-06-01T14:04:33.867Z+00:00

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).

2018-06-11T06:40:21.317Z+00:00

Has a bug been filed in GCC for this?

2022-10-21T20:46:20.47Z+00:00

In this particular case, there are two answers:

For C++14, gcc is right (i.e. constexpr static data member must have an initializer). For C++17 and beyond, gcc is wrong, since it refuses to compile conformant code.

Former case: In draft N3797 (C++14), 9.4.2.3 (Static data members) [class.static.data] (emphasis mine):

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.

See also: http://en.cppreference.com/w/cpp/language/static#Constant_static_members.

I said "in this particular case", because std::complex has a specialization for double that is a LiteralType. Therefore above rule applies. For general (i.e. non-literal) types, see codekaizers answer.

Latter case: For C++17, see xskxzr's answer.

answered Jun 1, 2018 at 7:57

andreee's user avatar

6 Comments

is c a literal? if not, then that doesn't apply.

2018-06-01T07:58:37.847Z+00:00

For specialization of double, std::complex is.

2018-06-01T08:01:21.833Z+00:00

@codekaizer Wrong paragraph. You want this.

2018-06-01T14:54:58.207Z+00:00

@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.

2018-06-02T06:11:35.717Z+00:00

@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).

2018-06-11T06:43:41.067Z+00:00

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

answered Jun 1, 2018 at 7:39

Joseph D.'s user avatar

1 Comment

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

2019-01-16T17:23:30.87Z+00:00

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.