Выберите каждый четный (или нечетный) аргумент в пакете параметров шаблона - PullRequest
4 голосов
/ 25 июня 2011

Я хотел бы разрешить использование класса, который я пишу, для указания в качестве параметров шаблона списка типов вместе со списком распределителей этих типов таким образом, что типы находятся в нечетных позициях, а распределители - в четных :

template<typename... T>
class MyClass {
  // Stuff inside
}

int main() {
  MyClass<SomeType1, AllocatorOfSomeType1> c1;
  MyClass<SomeType1, AllocatorOfSomeType1, 
          SomeType2, AllocatorOfSomeType2> c2;
  MyClass<SomeType1, AllocatorOfSomeType1, 
          SomeType2, AllocatorOfSomeType2,
          SomeType3, AllocatorOfSomeType3> c3;
  // And so on....
}

Внутренне имеет смысл иметь кортеж векторов типов для хранения:

std::tuple<std::vector<EveryOddTypeInParameterPack>...> m_storage_;

и кортеж распределителей для использования:

std::tuple<std::vector<EveryEvenTypeInParameterPack>...> m_storage_;

Как я могу на самом деле объявить эти кортежи в коде? В теории мне нужно как-то выбрать каждый нечетный / четный тип в пакете параметров - это возможно?

Ответы [ 4 ]

3 голосов
/ 26 июня 2011

Хотя код стал немного длиннее, я думаю, что механизм не имеет ненужные особенности.
Если я правильно понимаю вопрос, вероятно, следующий код будет соответствовать цели:

// push front for tuple
template< class, class > struct PFT;

template< class A, class... T > struct PFT< A, tuple< T... > > {
  typedef tuple< A, T... > type;
};

// for even
template< class... > struct even_tuple;

template< class A, class B > struct even_tuple< A, B > {
  typedef tuple< A > type;
};
template< class A, class B, class... T > struct even_tuple< A, B, T... > {
  typedef typename PFT< A, typename even_tuple< T... >::type >::type type;
};
// As for odd elements, in the same way as even(please see the test on ideone)

// objective type
template< class > struct storage_type;

template< class... T > struct storage_type< tuple< T... > > {
  typedef tuple< vector< T >... > type;
};

template< class... T >
struct MyClass {
  typename storage_type< typename even_tuple< T... >::type >::type
    m_storage_even_;
  typename storage_type< typename  odd_tuple< T... >::type >::type
    m_storage_odd_;
};

Вот тест на ideone .

2 голосов
/ 25 июня 2011

Возможно что-то вроде этого:

#include <tuple>

// Example receptacle    
template <typename ...Args> struct MyContainer;

// Tuple concatenator
template<typename PackR, typename PackL> struct cat;
template<typename ...R, typename ...L>
struct cat<std::tuple<R...>, std::tuple<L...>>
{
  typedef std::tuple<R..., L...> type;
};

// Even/Odd extractors
template <typename ...Args> struct GetEven;
template <typename ...Args> struct GetOdd;

template <typename E1, typename O1, typename ...Args>
struct GetEven<E1, O1, Args...>
{
  typedef typename cat<std::tuple<E1>, typename GetEven<Args...>::value>::type value;
};
template <typename E1, typename O1>
struct GetEven<E1, O1>
{
  typedef std::tuple<E1> value;
};

template <typename E1, typename O1, typename ...Args>
struct GetOdd<E1, O1, Args...>
{
  typedef typename cat<std::tuple<O1>, typename GetEven<Args...>::value>::type value;
};
template <typename E1, typename O1>
struct GetOdd<E1, O1>
{
  typedef std::tuple<O1> value;
};

// Tuple-to-Receptacle mover
template <typename Pack, template <typename ...T> class Receiver> struct Unpack;
template <typename ...Args, template <typename ...T> class Receiver>
struct Unpack<std::tuple<Args...>, Receiver>
{
  typedef Receiver<Args...> type;
};

// Example consumer
template <typename ...Args>
struct Foo
{
  typedef typename Unpack<typename GetEven<Args...>::value, MyContainer>::type EvenVector;
  typedef typename Unpack<typename GetOdd<Args...>::value, MyContainer>::type OddVector;

  EvenVector x;
  OddVector y;
};

Вам все еще нужно определить класс MyContainer, чтобы сделать что-то полезное с переменными параметрами, например, реализовать ваш кортеж векторов ... (почему бы не вектор кортежей?)

Кредиты brunocodutra за трюк с кортежем.

0 голосов
/ 07 июля 2019

Я знаю, что ваш вопрос изначально был помечен как "c ++ 11", но я думаю, что для потомков стоит отметить, что в C ++ 14 у вас есть доступ к make_index_sequence, и это делает все это довольно простым. Для фильтрации кортежа я бы начал с этой схемы: https://quuxplusone.github.io/blog/2018/07/23/metafilter/

И тогда мы получим что-то вроде этого ( Godbolt ):

template<bool> struct zero_or_one {
    template<class E> using type = std::tuple<E>;
};

template<> struct zero_or_one<false> {
    template<class E> using type = std::tuple<>;
};

template<class Tuple, class = std::make_index_sequence<std::tuple_size<Tuple>::value>>
struct just_evens;

template<class... Es, size_t... Is>
struct just_evens<std::tuple<Es...>, std::index_sequence<Is...>> {
    using type = decltype(std::tuple_cat(
        std::declval<typename zero_or_one<Is % 2 == 0>::template type<Es>>()...
    ));
};

Чтобы получить just_odds, вы должны изменить условие с Is % 2 == 0 на Is % 2 != 0.

Пример использования:

static_assert(std::is_same<
    just_evens<std::tuple<char, short, int, long, double>>::type,
    std::tuple<char, int, double>
>::value, "");
0 голосов
/ 25 июня 2011

это просто попытка

template<typename... T> class Myclass;

template<typename T1, typename allocT1>
class MyClass <T1, allocT1> {
  std::pair<T1, allocT1> myFirstArglist;
//and you have to do a check that allocT1::value_type is same as T1 or not
//or may be alloT1 is an allocator type or not(i'm thinking concepts, may be)
//this idea is inspired from Chris's comment
};

template<typename T1, typename allocT1, typename... T>
class Myclass<T1, allocT1, T...> {
std::pair<T1, allocT1> myFirstArglist;
Myclass<T>; //something like this
};

template<>
class Myclass<> {
//probably you would like some error message here
//when there are no types and containers
};

может быть, я не достаточно ясно, вы, вероятно, хотели бы прочитать http://www.open -std.org / jtc1 / sc22 / wg21 /docs /apers / 2006 / n2080.pdf

Также есть хороший пост, связанный с дизайном типов распределителя ... вы хотели бы взглянуть на: Шаблон проектирования C ++ для распределителявведите аргументы

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