enum vs constexpr for actual static constants inside classes
For the record, the static constexpr
version will work like you'd expected in C++17. From N4618 Annex D.1 [depr.static_constexpr]:
D.1 Redeclaration of
static constexpr
data members [depr.static_constexpr]For compatibility with prior C++ International Standards, a
constexpr
static data member may be redundantly redeclared outside the class with no initializer. This usage is deprecated. [Example:
struct A {
static constexpr int n = 5; // definition (declaration in C++ 2014)
};
constexpr int A::n; // redundant declaration (definition in C++ 2014)
—end example]
The relevant standard text that allows this is N4618 9.2.3 [class.static.data]/3:
[...] An inline static data member may 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.1). [...]
This comes with the same machinery that introduced the non-constexpr
version of the same thing, inline static data members.
struct A {
static inline int n = 5; // definition (illegal in C++ 2014)
};
inline int A::n; // illegal
You have three options here:
If your class is template, then put the definition of static member in header itself. Compiler is required to identify it as one definition only across multiple translation units (see [basic.def.odr]/5)
If your class is non-template you can easily put it in source file
Alternatively declare constexpr static member function getSomeValue():
class C { public: static constexpr int getSomeValue() { return 27; } };