Reputation: 5
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
Reputation: 217283
Use std::array
instead of regular array.
std::array
has already specialization for 0.
And in C++20,
[[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
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