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:

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

  2. If your class is non-template you can easily put it in source file

  3. Alternatively declare constexpr static member function getSomeValue():

    class C
    {
    public:
        static constexpr int getSomeValue() { return 27; }
    };