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