ARTICLE AD BOX
Asked 7 years, 7 months ago
Viewed 7k times
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 non-inline 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). 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. An inline static data member can be defined in the class definition and may specify a brace-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 brace-or-equal-initializer.
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
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.
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
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
Explore related questions
See similar questions with these tags.



