The major issue I found with in the question is as follows:
constexpr implies inline which means the object/function must be immediately defined not declared. In other words, constexpr demands complete definition, rather than a mere declaration. If object type is not implicitly default constructible, or is trivially default constructible, the initializer expression will be mandatory.
Thus the primary fix could be:
public:
//A full definition, not a declaration
constexpre static std::size_t s_array_size = 10;
private:
//of-course order of declaration matters too:
std::array<int, s_array_size> m_array;
In the above snippet s_array_size had to be defined before m_array were declared. The distinction between two terms definition and declaration can be looked up in any reliable C++ reference(Left for the reader 😈).
My preferred approach is logic inversion; I most often like to extract meta data out of object/class after its definition/declaration:
private:
std::array<int, 10> m_array;
public:
//Should compile, but probably won't:
constexpr static std::integral_costant
< std::size_t
, decltype(m_array)::size()>
s_array_size;
But it doesn't work, because std::array::size is not static. It's just constexpr. I'd rather see it consteval static. It's not hard to define a replacement template in personal codebase though. Of course for a trivial element type as int, I could product the result by instantiation: decltype(m_array){}.size(); but that doesn't sit right with me, because I might decide to change the element type in later revisions and that solution is not generic enough.
m_arrayisn't?m_array. E.g. tomorrow it can be a constexpr function instead of a static variable. Anyway that would be a reason to do so.