问题
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.
回答1:
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 :)
回答2:
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