How do I split variadic template arguments in two halves? Something like:
template struct a {
std::array p, q;
template <
Luc's solution is clean and straightforward, but sorely lacks fun.
Because there is only one proper way to use variadic templates and it is to abuse them to do crazy overcomplicated metaprogramming stuff :)
Like this :
template
std::array
split_array_range_imp(pack_indices pi, Ts... ts)
{
return std::array{get(ts...)...}; //TADA
}
template
std::array
split_array_range(Ts... ts)
{
typename make_pack_indices::type indices;
return split_array_range_imp(indices, ts...);
}
template
struct DoubleArray
{
std::array p, q;
template
DoubleArray (Ts ... ts) :
p( split_array_range(ts...) ),
q( split_array_range(ts...) )
{
}
};
int main()
{
DoubleArray<3> mya{1, 2, 3, 4, 5, 6};
std::cout << mya.p[0] << "\n" << mya.p[1] << "\n" << mya.p[2] << std::endl;
std::cout << mya.q[0] << "\n" << mya.q[1] << "\n" << mya.q[2] << std::endl;
}
It is quite short, except that we need to code some helper :
First we need the structure make_pack_indices, which is used to generate a range of integer at compile-time. For example make_pack_indices<5, 0>::type
is actually the type pack_indices<0, 1, 2, 3, 4>
template
struct pack_indices {};
template
struct make_indices_imp;
template
struct make_indices_imp, Ep>
{
typedef typename make_indices_imp, Ep>::type type;
};
template
struct make_indices_imp, Ep>
{
typedef pack_indices type;
};
template
struct make_pack_indices
{
static_assert(Sp <= Ep, "__make_tuple_indices input error");
typedef typename make_indices_imp, Ep>::type type;
};
We also need a get() function, very similar to std::get for tuple, such as std::get
return the Nth element of a parameters pack.
template
struct Get_impl
{
static R& dispatch(Tp...);
};
template
struct Get_impl
{
static R& dispatch(Head& h, Tp&... tps)
{
return Get_impl::dispatch(tps...);
}
};
template
struct Get_impl
{
static Head& dispatch(Head& h, Tp&... tps)
{
return h;
}
};
template
typename pack_element::type&
get(Tp&... tps)
{
return Get_impl::type, Ip, 0, Tp...>::dispatch(tps...);
}
But to build get() we also need a pack_element helper structure, again very similar to std::tuple_element, such as pack_element
is the Nth type of the parameters pack.
template
class pack_element_imp;
template
struct pack_types {};
template
class pack_element_imp >
{
public:
static_assert(Ip == 0, "tuple_element index out of range");
static_assert(Ip != 0, "tuple_element index out of range");
};
template
class pack_element_imp<0, pack_types >
{
public:
typedef Hp type;
};
template
class pack_element_imp >
{
public:
typedef typename pack_element_imp >::type type;
};
template
class pack_element
{
public:
typedef typename pack_element_imp >::type type;
};
And here we go.
Actually I don't really understand why pack_element and get() are not in the standard library already. Those helpers are present for std::tuple, why not for parameters pack ?
Note : My implementation of pack_element and make_pack_indices is a direct transposition of std::tuple_element and __make_tuple_indices implementation found in libc++.