Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Split paramter pack

I would like to split a template parameter pack. Something like this. How could I go about doing this?

template< typename... Pack >
struct TypeB : public TypeA< get<0, sizeof...(Pack)/2>(Pack...) >
             , public TypeA< get<sizeof...(Pack)/2, sizeof...(Pack)>(Pack...) > 
{
};

Here is my take on why this question is not a duplicate: I am looking for a generalised way to do this that will work when passing the split pack to other template classes - as shown above. As well as passing it to functions.

like image 951
Generic Name Avatar asked Oct 16 '22 15:10

Generic Name


1 Answers

With std::tuple (C++11) and std::index_sequence (C++14, but there are backports), the standard library contains everything to efficiently and somewhat conveniently split the pack.

template <class, class, class>
struct TypeBImpl;
template <std::size_t... N, std::size_t... M, class T>
struct TypeBImpl<std::index_sequence<N...>, std::index_sequence<M...>, T>
: TypeA<typename std::tuple_element_t<T, N>::type...>
, TypeA<typename std::tuple_element_t<T, M + sizeof...(N)>::type...>
{};

template <class... Ts>
struct TypeB
: TypeBImpl<
    std::make_index_sequence<sizeof...(Ts) / 2>,
    std::make_index_sequence<(sizeof...(Ts) + 1) / 2>,
    std::tuple<std::enable_if<1, Ts>...>
>
{};

I used an intermediate base for convenience, which has the added advantage of keeping the helper-types for re-use in members.


If you don't need it, or its existence in RTTI is inconvenient, there are other solutions:

template <class T, std::size_t N, std::size_t... M>
auto TypeA_part_impl(std::index_sequence<M...>)
-> TypeA<typename std::tuple_element_t<T, N + M>::type...>;

template <bool tail, class... Ts>
using TypeA_part = decltype(TypeA_part_impl<
    std::tuple<std::enable_if<1, Ts>...>,
    tail * sizeof...(Ts) / 2>(
    std::make_index_sequence<(sizeof...(Ts) + tail) / 2>()));

template <class... Ts>
struct TypeB : TypeA_part<0, Ts...>, TypeA_part<1, Ts...>
{
};

I'm using std::enable_if<1, T> as a convenient vehicle to transfer arbitrary type-information, even if the type is so irregular it cannot be stored in a std::tuple, or is incomplete. No need to define my own.

like image 52
Deduplicator Avatar answered Oct 21 '22 14:10

Deduplicator