How to (or is it possible to) unpack a parameter pack with a numeric sequence? For example,
template <typename C, typename... T>
C* init_from_tuple(bp::tuple tpl)
{
return new C{bp::extract<T>("magic"(tpl))...}; // <--
}
which the <-- line should expand to
return new C{bp::extract<T0>(tpl[0]),
bp::extract<T1>(tpl[1]),
.....
bp::extract<Tn>(tpl[n])};
where n == sizeof...(T) - 1.
The purpose is to create a __init__ function for Boost.Python which accepts a tuple with predefined types.
Actually, it is possible for the unpack operations to target two different packs of parameters at once (I think they need be of equal length). Here we would like a pack of types, and a pack of numbers.
Something akin to:
template <typename C, typename... T, size_t... N>
C* init_from_tuple_impl(bp::tuple tpl) {
return new C{ bp::extract<T>(tpl[N])... };
}
We "just" need to generate the pack of indices:
template <size_t... N> struct Collection {};
template <typename C> struct ExtendCollection;
template <size_t... N>
struct ExtendCollection< Collection<N...> > {
typedef Collection<N..., sizeof...(N)> type;
};
template <typename... T>
struct GenerateCollection;
template <>
struct GenerateCollection<> { typedef Collection<> type; };
template <typename T0, typename... T>
struct GenerateCollection<T0, T...> {
typedef typename ExtendCollection<
typename GenerateCollection<T...>::type
>::type type;
};
And then use it:
template <typename C, typename... T, size_t... N>
C* init_from_tuple_impl(bp::tuple tpl, Collection<N...>) {
return new C { bp::extract<T>(tpl[N])... };
}
template <typename C, typename... T>
C* init_from_tuple(bp::tuple tpl) {
typename GenerateCollection<T...>::type collection;
return init_from_tuple_impl<C, T...>(tpl, collection);
}
In action at Ideone.
We can witness the correctness by making a "mistake" in the implementation of init_from_tuple_impl (remove the new for example):
template <typename C, typename... T, size_t... N>
C* init_from_tuple_impl(bp::tuple tpl, Collection<N...>) {
return C { bp::extract<T>(tpl[N])... };
}
In action at Ideone:
prog.cpp: In function 'C* init_from_tuple_impl(bp::tuple, Collection<N ...>)
[with
C = bp::Object,
T = {int, float, char},
unsigned int ...N = {0u, 1u, 2u},
bp::tuple = std::basic_string<char>
]':
Exactly what we wanted :)
Its possible if you first extract the parameters into their own pack and then call the constructor. its far from finished, but you get the general idea:
template <typename C, int N, typename... T>
C* init_from_tuple(bp::tuple tpl, T... args) // enable_if N == sizeof...(T)
{
return new C{args...};
}
template <typename C, int N, typename T0, typename... T>
C* init_from_tuple(bp::tuple tpl, T... args) // enable_if N != sizeof...(T)
{
return init_from_tuple<C, N + 1>(tpl, args, bp::extract<T0>(tpl[N]));
}
template <typename C, typename... T>
C* init_from_tuple(bp::tuple tpl, T... args)
{
return init_from_tuple<C, 0, T...>(tpl, args);
}
Use boost's enable_if to make the places indicated only enabled in some cases, and probably the template arguments need some changes, but this is a start.
来源:https://stackoverflow.com/questions/8027952/how-to-unpack-a-variadic-template-parameter-with-a-numeric-sequence