There is no need for variadics, a recursive typedef
is sufficient to generate those types at compile time.
How is is implemented ?
1) Provide a template with 2 arguments : the vector elements type (T
), and the desired dimension of the structure (size_t N
). Declare a typedef type
: it will be based on the declaration of type
for the template instantiated with the depth N-1
, hence the recursion.
template<typename T, size_t N>
struct VectorGenerator
{
typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};
2) Provide a termination case for ending the recursion, here a specialization of our template with the dimension 0, declaring the type of a usual std::vector<T>
.
template<typename T>
struct VectorGenerator<T, 0>
{
typedef std::vector<T> type;
};
How to use it ?
We can now declare a vector v
of type VectorGenerator<T, N>::type
:
VectorGenerator<double, 4>::type v; // v as a depth of 4 and handle double
But it's not very readable or convenient, and pretty verbose. Let's introduce new names for our types.
This is the perfect case for template aliasing, with the (C++11) using
keyword for aliasing. We have 2 different ways of aliasing :
1) Declare an alias for a particular dimension and type, here we call it V3 for N=3
and T=double
:
using V3 = VectorGenerator<double, 3>::type; // Alias
V3 v; // Use the alias
Or,
2) Declare a template alias for a particular type, leaving the dimension as a template parameter:
template <size_t N>
using V = typename VectorGenerator<double, N>::type; // Alias
V<3> v; // Use the Alias
Final code sample:
template<typename T, size_t N>
struct VectorGenerator
{
typedef std::vector< typename VectorGenerator<T, N-1>::type > type;
};
template<typename T>
struct VectorGenerator<T, 0>
{
typedef std::vector<T> type;
};
// Alias for V3, V2 ... usage
using V3 = VectorGenerator<double, 3>::type;
using V2 = VectorGenerator<double, 2>::type;
// Alias for V <k> usage
template <size_t N>
using V = typename VectorGenerator<double, N>::type;
int main() {
V<3> v3;
V<2> v2;
v3.push_back(v2);
return 0;
}
Notes :
- Consider the Boost MultiDimensional Array library.
- I am not sure of what your final goal is, but this might well be an overkill.
- As for your second edit, declaring a
tuple
with multiple vectors of different dimensions is now easy :
Example:
auto tower = std::tuple<V<1>, V<2>, V<3>>(v1, v2, v3);
For the generic tuple generation of multiple "towers", @mpark gave a working C++14 solution, I adapt it here to my code sample:
template <typename T>
struct identity { using type = T; };
// Generate a tuple of towers by mapping index_sequence over gen_tower.
template <typename T, std::size_t... Is>
std::tuple<VectorGenerator<T, Is>...> gen_towers_impl(std::integer_sequence<Is...>);
// Make an index_sequence for N and use gen_towers_impl.
template <typename T, std::size_t N>
struct gen_towers
: identity<decltype(gen_towers_impl<T>(std::make_index_sequence<N>()))> {};
// Convenience type aliases
template <typename T, std::size_t N>
using gen_towers_t = typename gen_towers<T, N>::type;
You will need -std=c++1y
to compile it (and include <utility>
and <tuple>
headers)
See a working example here.