I need to generate a tuple of class templates given an integer list as a variadic argument. The result I want to achieve is presented in the example below, but doesn´t compile:
template <unsigned int First, unsigned int... Is> using remove_first = std::integer_sequence<unsigned int, Is...>; template <unsigned int... Is, unsigned int Last> // Invalid using remove_last = std::integer_sequence<unsigned int, Is...>; template <unsigned int N_prev, unsigned int N> class A {}; template <unsigned int... Is> class B { std::tuple<A<remove_last<Is>, remove_first<Is>>...> object; }; int main() { B<3, 4, 6, 2> b; // <<= b.object is of type: std::tuple<A<3,4>, A<4,6>, A<6,2>> }
Is it possible to achieve in a similar way?
Answer
First of all – variadic pack, in general, must be last – so this will not compile:
template <unsigned int... Is, unsigned int Last> // Invalid using remove_last = std::integer_sequence<unsigned int, Is...>;
But you do not need neither remove_first or remove_last. You need to store these pairs A<_, _>
one by one in internal template of helper template. I invented(of course, I have no idea I am the first one) this technique when I wanted to implement flat union in this toy project.
So here the code with comments:
#include <tuple> #include <type_traits> template <unsigned int N_prev, unsigned int N> class A {}; // The helper type template <unsigned int... Is> struct DefineAPairs; template <unsigned int I1, unsigned I2, unsigned int... Is> struct DefineAPairs<I1, I2, Is...> { // in the following line pair A<I1, I2> is added at the proper // position in nested DefineAPairs template <typename ...FirstPairs> using type = typename DefineAPairs<I2, Is...> ::template type<FirstPairs..., A<I1, I2>>; // here ^^^^^^^^^ }; template <unsigned int I1, unsigned I2> struct DefineAPairs<I1, I2> { // this is sentinel implementation template <typename ...FirstPairs> using type = std::tuple<FirstPairs..., A<I1, I2>>; }; template <unsigned int... Is> class B { public: using type = typename DefineAPairs<Is...>::template type<>; type object; }; int main() { B<3, 4, 6, 2> b; // <<= b.object is of type: std::tuple<A<3,4>, A<4,6>, A<6,2>> // the proof it works static_assert(std::is_same<std::tuple<A<3,4>, A<4,6>, A<6,2>>, decltype(b.object)>::value); }
And demo.