This question can be split into two parts.
- Get the dimensions from the input template parameter
T.
- Constructor accepts different numbers of values as run-time dimensions.
Let's look at it one by one.
To solve the first problem, a non-type typelist is used to represent the dimensions.
template <size_t... Ns>
struct Dimension {
template <size_t N>
using prepend = Dimension<N, Ns...>;
};
0 means the dimension is determined at run-time. Now we construct a template class hoping to decompose its template parameter into the dimensions we want.
template <typename>
struct Analysis;
// Analysis<int**> -> Dimension<0, 0>
// Analysis<int[1][2] -> Dimension<1, 2>
// Analysis<int*[3]> -> Dimension<0, 3>
Using alias template nested inside specialization to decompose the pointers / [] layer by layer recursively. Compile-time dimensions and run-time dimensions are represented separately and joined together.
Whenever meeting a *, prepend a 0 in the dynamic dimension. Whenever meeting a [N], prepend an N in the static dimension.
template <typename T>
struct Analysis {
using sdim = Dimension<>; // static
using ddim = Dimension<>; // dynamic
using dim = Dimension<>; // all
};
template <typename T, size_t N>
struct Analysis<T[N]> {
using nested = Analysis<T>;
using sdim = typename nested::sdim::template prepend<N>;
using ddim = typename nested::ddim;
using dim = join_t<ddim, sdim>;
};
template <typename T>
struct Analysis<T*> {
using nested = Analysis<T>;
using sdim = typename nested::sdim;
using ddim = typename nested::ddim::template prepend<0>;
using dim = join_t<ddim, sdim>;
};
T[] is similar to T*, not shown here. Now we have,
static_assert(std::is_same_v<
Analysis<int[1][2][3]>::dim,
Dimension<1, 2, 3>>);
static_assert(std::is_same_v<
Analysis<int***>::dim,
Dimension<0, 0, 0>>);
static_assert(std::is_same_v<
Analysis<int*[1][2]>::dim,
Dimension<0, 1, 2>>);
Demo
Since we've got the dimensions, constructing a View-like thing is simple. Its constructor accepts a bunch of parameters with a default value as run-time dimensions.
template <typename T>
struct View {
using dim = typename Analysis<T>::dim;
View(size_t dim0 = -1, size_t dim1 = -1, size_t dim2 = -1) { // you could write more
if (get_v<dim, 0> == 0 && dim0 != -1) {
// run-time
}
if (get_v<dim, 1> == 0 && dim1 != -1) {}
if (get_v<dim, 2> == 0 && dim2 != -1) {}
}
};
Demo