Ikarus
Ikarus

Reputation: 5

Templated data type that might have an array of length zero

I want to have a data type, which has a certain templated amount of extra information, but the extra information might be non-existent.

My first idea was just doing this:

template <size_t SIZE>
class Data
{
    int a;
    int bs[SIZE];

public:
    Data(int a, int bs[SIZE]) : a(a),  bs(bs) {};
};

But after reading some other questions about zero-sized arrays here, this seems to result in troubles if I instantiate the template with SIZE = 0, in this case my compiler will give my an <error-type> if I try to call the constructor with Data<0> d(1, {});

One obvious solution would be to create an extra type for this case:

class DataZero
{
    int a;

public:
    Data(int a) : a(a) {};
};

but I would immensely prefer a solution, which would allow me to keep the templates everywhere and allow me to write Data<0> if that is possible. Also, maybe I am just instantiating Data<0> wrong, but any input on this matter is greatly appreciated.

Upvotes: 0

Views: 47

Answers (2)

Jarod42
Jarod42

Reputation: 217283

Use std::array instead of regular array.

std::array has already specialization for 0.

And in C++20,

  • attribute [[no_unique_address]] allows compiler to optimize in the case of SIZE==0.
  • requires allows to place both your constructors in same class, and discard the wrong depending of the instantiation:
template <size_t SIZE>
class Data
{
    int a;
    [[no_unique_address]] std::array<int, SIZE> bs;

public:
    Data(int a) requires (SIZE == 0) : a(a),  bs() {}
    Data(int a, std::array<int, SIZE> bs) requires (SIZE != 0) : a(a),  bs(bs) {}
};

Upvotes: 1

R Sahu
R Sahu

Reputation: 206607

You can do that using template specialization.

template <>
class Data<0>
{
    int a;

  public:
    Data(int a) : a(a) {}
};

However, when creating an object of type Data<0>, you'll have to use

Data<0> d(1);

If you must support use of

Data<0> d(1, {});

you can use a place holder argument that is ignored.

template <>
class Data<0>
{
    int a;

  public:
    Data(int a, int b) : a(a) {}
};

Upvotes: 1

Related Questions