Как распаковать шаблоны с переменным числом числовой последовательности?
Как (или возможно ли) распаковать пакет параметров с числовой последовательностью? Например,
template <typename C, typename... T>
C* init_from_tuple(bp::tuple tpl)
{
return new C{bp::extract<T>("magic"(tpl))...}; // <--
}
Которую строка <--
должна расширить до
return new C{bp::extract<T0>(tpl[0]),
bp::extract<T1>(tpl[1]),
.....
bp::extract<Tn>(tpl[n])};
Где n == sizeof...(T) - 1
.
Цель состоит в том, чтобы создать функцию__ init _ _ для Boost.Python, который принимает кортеж с предопределенными типами.
2 ответа:
На самом деле, операции распаковки могут быть нацелены на два разных пакета параметров одновременно (я думаю, что они должны быть одинаковой длины). Здесь мы хотели бы иметь пачку типов и пачку чисел.
Что-то вроде:
template <typename C, typename... T, size_t... N> C* init_from_tuple_impl(bp::tuple tpl) { return new C{ bp::extract<T>(tpl[N])... }; }
Нам "просто" нужно сгенерировать пакет индексов:
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; };
И затем использовать его:
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); }
В действии наИдеоне .
Мы можем засвидетельствовать правильность, сделав "ошибку" в реализации
init_from_tuple_impl
(удалитьnew
например):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])... }; }
В действии на Идеоне :
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> ]':
Именно то, что мы хотели :)
Это возможно, если вы сначала извлекаете параметры в их собственный пакет, а затем вызываете конструктор. его далеко не закончили, но вы получите общую идею:
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); }
Используйте boost
enable_if
, чтобы сделать указанные места включенными только в некоторых случаях, и, вероятно, аргументы шаблона нуждаются в некоторых изменениях, но это начало.