Как распаковать параметр шаблона с числовой последовательностью? - PullRequest
3 голосов
/ 06 ноября 2011

Как (или возможно) распаковать пакет параметров с числовой последовательностью?Например,

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 ]

3 голосов
/ 06 ноября 2011

На самом деле, операции распаковки могут нацеливаться на два разных пакета параметров одновременно (я думаю, что они должны быть одинаковой длины). Здесь нам нужна пачка типов и пачка цифр.

Что-то похожее на:

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])... };
}

В действии на 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>
]':

Именно то, что мы хотели:)

1 голос
/ 06 ноября 2011

Это возможно, если вы сначала извлечете параметры в их собственный пакет, а затем вызовете конструктор.Это далеко не закончено, но вы получите общее представление:

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, чтобы сделать указанные места включенными только в некоторых случаях, и, вероятно, аргументы шаблона требуют некоторых изменений, но этоначать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...