Преобразование вариативных параметров шаблона в другие типы

Как преобразовать типы из параметров вариативного шаблона в другой тип?

Например:

template <typename... T>
struct single
{
   std::tuple<T...> m_single;
};

template <typename... T>
struct sequences
{
   single<T...> get(size_t pos)
   {
       // I don't know how to convert here
       return std::make_tuple(std::get<0>(m_sequences)[pos]... std::get<N>(m_sequences)[pos]);
   }

   template <size_t Idx>
   std::vector<
      typename std::tuple_element<Idx, std::tuple<T...>>::type
      >
   get_sequence()
   {
      return std::get<Idx>(m_sequences);
   }

   std::tuple<T...> m_sequences; // std::tuple<std::vector<T...>> I don't know how to conver here
};

Я хочу написать так:

sequences<int, double, double> seq;
single<int, double, double> sin = seq.get(10);

И иметь std::tuple<std::vector<int>, std::vector<double>, std::vector<double>> в последовательности структур. И получить от этого сингл.

std::vector<single<T...>> - плохая идея для меня, потому что мне нужно заполнить одну последовательность, и ее легко скопировать.

Является ли это возможным?

Большое тебе спасибо. Извините за мой плохой английский.


person Max    schedule 08.03.2011    source источник


Ответы (2)


Вы можете сделать больше, чем просто развернуть пакет параметров с переменным числом аргументов в виде простого списка: вы также можете развернуть выражение. Таким образом, m_sequences может быть кортежем векторов, а не кортежем элементов:

template <typename... T>
struct sequences
{
   std::tuple<std::vector<T>...> m_sequences;
};

Вы также можете проделать изящные трюки с пакетами параметров, чтобы выбрать соответствующий элемент из вектора:

template<size_t ... Indices> struct indices_holder
{};

template<size_t index_to_add,typename Indices=indices_holder<> >
struct make_indices_impl;

template<size_t index_to_add,size_t...existing_indices>
struct make_indices_impl<index_to_add,indices_holder<existing_indices...> >
{
    typedef typename make_indices_impl<
        index_to_add-1,
        indices_holder<index_to_add-1,existing_indices...> >::type type;
};

template<size_t... existing_indices>
struct make_indices_impl<0,indices_holder<existing_indices...> >
{
    typedef indices_holder<existing_indices...>  type;
};

template<size_t max_index>
typename make_indices_impl<max_index>::type make_indices()
{
    return typename make_indices_impl<max_index>::type();
}



template <typename... T>
struct sequences
{
    std::tuple<std::vector<T>...> m_sequences;

    template<size_t... Indices>
    std::tuple<T...> get_impl(size_t pos,indices_holder<Indices...>)
    {
        return std::make_tuple(std::get<Indices>(m_sequences)[pos]...);
    }

    std::tuple<T...> get(size_t pos)
    {
        return get_impl(pos,make_indices<sizeof...(T)>());
    }
};
person Anthony Williams    schedule 08.03.2011

Хорошо, это может показаться излишним, но как насчет этого: насколько я знаю, единственный вариант «повторять» вариативные числа - это использовать нотацию <head, tail...> со специализацией шаблона для простого случая <head-only>.

Поэтому вы можете попробовать что-то вроде этого:

простой случай:

template <typename T>
struct sequences
{
   std::tuple<T> get(size_t pos)
   {
     return values[pos];
   }

   std::vector<T> get_sequence()
   {
      return values;
   }

   std::vector<T> values;
};

рекурсивный случай:

template <typename T, typename ...U>
struct sequences
{
   std::tuple<T, std::tuple<U...> > get(size_t pos)
   {
     return std::make_tuple(values[pos], remainder->get(pos));
   }

  template <size_t Idx>
  std::vector<
      typename std::tuple_element<Idx, std::tuple<T...>>::type
    > get_sequence()
  {
    return get_sequence_internal<
         typename std::tuple_element<Idx, std::tuple<T...>>::type, Idx
       >();
   }

   template <typename V, 0>
   std::vector<V> get_sequence_internal()
   {
      return values;
   }

   template <typename V, size_t Idx>
   std::vector<V> get_sequence()
   {
      return remainder->getSequence_internal<V, Idx-1>();
   }



   std::vector<T> values;
   sequences<U...>* remainder;
};

Отказ от ответственности: не тестировался, даже не компилировался, но я полагаю, вы поняли основную идею. Остаются как минимум две проблемы:

  1. Возвращаемое значение get() - это не ваша единственная структура, а цепочка кортежей. Возможно, вы сможете рекурсивно разцепить его с помощью _6 _...
  2. Я не знаю, вызывает ли специализация get_sequence_internal ошибку времени компиляции, потому что тип V может отличаться от T.
person Jonas Bötel    schedule 08.03.2011