How to specify the size of a class array ?

Templates are your best bet, none of the side effects of #defines, a template type is bound to its parameters so consider a class:

template< int V > struct Foo{ static const int MyNum = V; };

This struct is global, you are guaranteed that "Foo< 5 >::MyNum" is always the same value, no matter what compilation unit. This may not be the clearest example, if MyNum was equal to something else other than V it would still have the same guarantee.

You can also put the class definition in a cpp file, I'll describe below:

lib.h

template< typename T >
  class Foo{
    public:
      Foo( T t_In );
      T Value( void );
    private:
      T t_Data;
};

lib.cpp

  #include "lib.h"

  template< typename T >
    Foo< T >::Foo( T t_In ) : t_Data( t_In ) {}

  template< typename T >
    Foo< T >::Value( void ){ return this->t_Data; }

This set up will lead to a linker error. This error is because the compilation unit cannot see the definition of the template. To fix this you can do two things: instantiate types where the definition is available, or use the the definition rather than the declaration.

If you know what range/discrete values/types users may select for the template you can instantiate them directly in the cpp ( lib.cpp ) file

//Add instantiations below definitions in cpp file.
template class Foo< bool >;
template class Foo< char >;
template class Foo< long >;

In your sketch you can include the header file and happily use the template with bool, char, and long however int will cause an error.
This is a basic way of stopping programmers from misusing the library with bad inputs.

The other way is simply include the cpp file instead of the header, solving the missing definition error.

Here is my template array class you can give a try:

template< typename _Type, uint16_t _Len > 
  struct MPLArray{
    enum{ 
      Length = _Len,
      Size = sizeof( _Type ) * _Len,
    };
  _Type& operator[]( uint16_t u_Index ) { return this->t_Data[ u_Index ]; }
  operator _Type*() { return this->t_Data; }
  operator const _Type*() const { return this->t_Data; }
  
  _Type t_Data[ Length ];
};	

void loop(){
  MPLArray< bool, 5 > bb = { true, true, true, false, false };
  bool *bp = bb;
  Serial.print( bb[0] );
  Serial.print( *( bp + 3 ) );
  Serial.print( bb.Length );
  Serial.print( bb.Size );
}

You could also create as a variable in a class, or derive a class from it to inherit the functionality.