How to define the size of an array that is a static member of a non instanciable class?

190 views Asked by At

I'm writing a class I don't want to instantiate. All its members are static. This class represents a peripheral of a microcontroller. Since there is only one instance of that peripheral in the microcontroller doesn't make sense to me create instances of that class. The class only groups the data and functions of that peripheral.

One of the data members of the class is an array whose size the user of the class should define at compile time. If I could create objects of this class I know I could initialize consts in the initializer list of a constructor, but I really don't want to create instances of this class. Maybe I could use templates and set the array size as the template parameter, but I would need to use something like my_class<5>::do_something() for every member call. Is there a simpler way to solve this problem? I'd like to make my class something like this:

class my_class
{
private:
    static const int _size;
    static int _array[_size];
public:
    static void array_size(int size) { _size = size; }
    static void do_something() { /* .... */ } 
};
4

There are 4 answers

0
W.F. On BEST ANSWER

Consider using class template parametrized with constexpr array size and then create an alias:

#include <array>

template <std::size_t Size>
class my_class_impl {
private:
    static constexpr std::size_t size = Size;
    static std::array<int, Size> arr;
public:
    static void do_something() { /* .... */ }
};

template <std::size_t Size>
std::array<int, Size> my_class_impl<Size>::arr;

using my_class = my_class_impl<10>;

int main() {
    my_class::do_something();
}
5
mgarey On

Your main requirement is that the array size is set at compile time. This is more C-ish, something you'd generally avoid when writing C++, but in your case, it might make more sense to use macros, such as

#define ARRAY_SIZE 
... somewhere in your class ...
static int array_name[ARRAY_SIZE];
0
AudioBubble On

Your best bet is probably a good old define.

Here's how I'd structure this (using namespaces, as it's the idiomatic way to do static-only classes):

peripheral.h:

namespace peripheral {
  void do_something();
}

peripheral.cpp:

#ifndef PERIPH_ARRAY_SIZE
#  error "please define the size of array"
#endif

namespace {
  int _array[PERIPH_ARRAY_SIZE];
}

namespace peripheral {
  void do_something() {...}
}
8
tinstaafl On

One way to allow the user to set the size, would be to change the array to a vector. Since it's private you control how it's used. A simple bool will restrict whether it's sized once and making sure it does get sized:

class my_class
{
private:
    static const int _size = 10;
    static vector<int> _array;
    static bool arraySized;
public:
    static void array_size( int size = _size ) 
    {
        if ( !arraySized )
        {
            _array = vector<int>( size );
            arraySized = true;
        }
    }
    static void do_something() 
    {
        if ( arraySized )
        {
            /* .... */
        }
    }
};

While not at compile time, it does have the same effect.

A couple of other things to think about, using a template based approach can allow more than 1 instance of that class to be created. Which can break the singularity principle that you seem to want

using my_class = my_class_impl<10>;

using my_class2 = my_class_impl<20>;
int main() {
    my_class::do_something();
    my_class2::do_something();
}

The other thing is that the newest Atmel framework does include headers for vectors. The information you referenced must be out of date.