The most direct subproblem is in the land of typelists:
template <class... Ts> struct typelist { using type = typelist; static constexpr std::size_t size = sizeof...(Ts); }; template <class T> struct tag { using type = T; }; template <std::size_t N, class TL> struct head_n { using type = ???; };
Now, head_n is just a matter of simple recursion - move an element from one list to another list N times starting from an empty list.
template <std::size_t N, class R, class TL> struct head_n_impl; // have at least one to pop from and need at least one more, so just // move it over template <std::size_t N, class... Ts, class U, class... Us> struct head_n_impl<N, typelist<Ts...>, typelist<U, Us...>> : head_n_impl<N-1, typelist<Ts..., U>, typelist<Us...>> { }; // we have two base cases for 0 because we need to be more specialized // than the previous case regardless of if we have any elements in the list // left or not template <class... Ts, class... Us> struct head_n_impl<0, typelist<Ts...>, typelist<Us...>> : tag<typelist<Ts...>> { }; template <class... Ts, class U, class... Us> struct head_n_impl<0, typelist<Ts...>, typelist<U, Us...>> : tag<typelist<Ts...>> { }; template <std::size_t N, class TL> using head_n = typename head_n_impl<N, typelist<>, TL>::type;
Going from this to your specific problem I leave as an exercise to the reader.
An alternate approach is via concatenation. Convert every element of a typelist<Ts...> into either a typelist<T> or a typelist<>, and then concat them all together. concat is straightforward:
template <class... Ts> struct concat { }; template <class TL> struct concat<TL> : tag<TL> { }; template <class... As, class... Bs, class... Rest> struct concat<typelist<As...>, typelist<Bs...>, Rest...> : concat<typelist<As..., Bs...>, Rest...> { };
And then we can do:
template <std::size_t N, class TL, class = std::make_index_sequence<TL::size>> struct head_n; template <std::size_t N, class... Ts, std::size_t... Is> struct head_n<N, typelist<Ts...>, std::index_sequence<Is...>> : concat< std::conditional_t<(Is < N), typelist<Ts>, typelist<>>... > { }; template <std::size_t N, class TL> using head_n_t = typename head_n<N, TL>::type;
The advantage of this latter approach is that concat can be replaced in C++17 by a fold-expression given an appropriate operator+:
template <class... As, class... Bs> constexpr typelist<As..., Bs...> operator+(typelist<As...>, typelist<Bs...> ) { return {}; }
which allows:
template <std::size_t N, class... Ts, std::size_t... Is> struct head_n<N, typelist<Ts...>, std::index_sequence<Is...>> { using type = decltype( (std::conditional_t<(Is < N), typelist<Ts>, typelist<>>{} + ... + typelist<>{}) ); };