Преобразуйте параметры шаблона переменной в другие типы - PullRequest
12 голосов
/ 08 марта 2011

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

Например:

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...>> - плохая идея для меня, потому что мне нужно заполнить одну последовательность, и ее легко скопировать.

Возможно ли это?

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

Ответы [ 2 ]

15 голосов
/ 08 марта 2011

Вы можете сделать больше, чем просто развернуть пакет параметров с переменными параметрами в виде простого списка: вы также можете расширить выражение.Поэтому 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)>());
    }
};
2 голосов
/ 08 марта 2011

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

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

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

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() - это не единственная структура, а цепочка кортежей. Возможно, вы можете отцепить его рекурсивно с помощью std::get<0> ...
  2. Я не знаю, генерирует ли специализация get_sequence_internal ошибку времени компиляции, поскольку тип V может отличаться от T.
...