Reputation:
I made a generic n-dimensional array class, but I want to make it safer with some compile-time checks.
The constructor and operator()
are only expected to work correctly when the number of arguments given equals dimension
. Still, if I write code like
Array<int, 2> a(1, 2, 3); //3 dimensions for a 2d array == crash
or
Array<int> a(1); //plain 1D array
std::cout << a(1, 2); //segfault
it just silently compiles, and I need to run a debugger, but it's quite confusing to debug variadic templates.
Can you think of a good way to provide a compile time check for the correct number of arguments matching the dimension?
template<typename T, int dimension = 1>
class Array
{
private:
std::unique_ptr<T[]> pointer;
int size[dimension];
int realSize;
public:
Array()
{
}
template<typename... Ns>
Array(Ns... ns)
: realSize(1)
{
create(1, ns...);
}
private:
template<typename... Ns>
void create(int d, int n, Ns... ns)
{
realSize *= n;
size[d - 1] = n;
create(d + 1, ns...);
}
void create(int d)
{
pointer = std::unique_ptr<T[]>(new T[realSize]);
}
int computeSubSize(int d) const
{
if (d == dimension)
{
return 1;
}
return size[d] * computeSubSize(d + 1);
}
template<typename... Ns>
int getIndex(int d, int n, Ns... ns) const
{
return n * computeSubSize(d) + getIndex(d + 1, ns...);
}
int getIndex(int d) const
{
return 0;
}
public:
template<typename... Ns>
T& operator()(Ns... ns) const
{
return pointer[getIndex(1, ns...)];
}
int getSize(int d = 1) const
{
return size[d - 1];
}
};
Upvotes: 3
Views: 1354
Reputation: 206567
You can add compile time assert statements at the right places to prevent code like
Array<int, 2> a1(1, 2, 3);
and
Array<int> a3(1);
std::cout << a3(1, 2);
from being compiled.
Here's once place:
template<typename... Ns>
Array(Ns... ns)
: realSize(1)
{
static_assert(sizeof ...(Ns) == dimension, "Incorrect number of arguments");
create(1, ns...);
}
That prevents the line
Array<int, 2> a1(1, 2, 3);
from being compiled.
Another place:
template<typename... Ns>
T& operator()(Ns... ns) const
{
static_assert(sizeof ...(Ns) == dimension, "Incorrect number of arguments");
return pointer[getIndex(1, ns...)];
}
That prevents
Array<int> a3(1);
std::cout << a3(1, 2);
from being compiled.
Here are some valid statements:
Array<int, 2> a2(1, 2);
Array<int> a3(1);
std::cout << a3(0);
Upvotes: 1