Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to interleave parameter packs?

Is it possible, with C++11/14/1z, to have a templated construct with two parameter packs, and within it, instantiate some other templated construct with the two packs inteleaved? i.e. if the first pack is T1_1, T1_2, T1_3 and the second pack is T2_1, T2_2 and T2_3, the interleaved pack will be T1_1, T2_1, T1_2, T2_2, T1_3, T2_3? My guess would be "no", since an ellipsis should not be able to apply to two parameter pack element designators; but perhaps some kind of tuple-construction or recursive-instantiation trick could work?

Edit: Let me be explicit in assuming the packs have equal lengths (sizeof... values). A solution for packs of different lengths would be nice provided it doesn't make things much more convoluted.

like image 352
einpoklum Avatar asked Jun 22 '16 19:06

einpoklum


People also ask

What is a parameter pack?

[edit] A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments. A template with at least one parameter pack is called a variadic template.


2 Answers

All the individual pieces for this have actually already been added to the standard. I can't test this myself right now but the idea should work.

template <class Tuple1, class Tuple2, std::size_t ... indices>
auto interleave(Tuple1 t1, Tuple2 t2, std::integer_sequence<std::size_t, indices...>)
{
    return std::tuple_cat(std::make_tuple(std::get<indices>(t1),
                                          std::get<indices>(t2))...);
}


template <class Tuple1, class Tuple2>
auto interleave(Tuple1 t1, Tuple2 t2)
{
    return interleave(t1, t2, std::make_index_sequence<std::tuple_size<Tuple1>::value>());
}
like image 146
SirGuy Avatar answered Oct 13 '22 20:10

SirGuy


Using tuple_cat is overkill. Not to mention unnecessarily constraining.

Trivial pack class:

template<class...> struct pack {};

A variadic concat, fairly trivial to write:

template<class T = pack<>, class...> 
struct concat { using type = T; };

template<class... T1, class... T2, class... Ts>
struct concat<pack<T1...>, pack<T2...>, Ts...> 
    : concat<pack<T1..., T2...>, Ts...> {};

template<class... Ts> 
using concat_t = typename concat<Ts...>::type;

Then interleave itself is equally trivial - expand into pack of two types, then concatenate them:

template<class... Us>
struct interleave {
     template<class... Vs>
     using with = concat_t<pack<Us, Vs>...>;
};

Demo.

like image 31
T.C. Avatar answered Oct 13 '22 20:10

T.C.