I have a Foo
class that includes an array and a static constexpr
variable. As a general convention, I want to write public
and private
variables respectively. But, compiler error occurs 's_array_size' was not declared in this scope
when I compile the header code below.
#ifndef FOO_H
#define FOO_H
#include <array>
#include <cstddef>
class Foo
{
public:
Foo();
std::array<int, s_array_size> m_array;
private:
constexpr static size_t s_array_size;
}
#endif
I can make s_array_size
public or I can move the private
section above the public
section to solve the problem. However, I don't like these solutions as I want two sections public
and private
respectively. Is there any way to declare a constexpr static
variable inside a class?
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.