Как я могу иметь несколько пакетов параметров в шаблоне с переменными параметрами? - PullRequest
46 голосов
/ 23 марта 2012

Функция one () принимает один пакет параметров.Функция two () принимает два.Каждая упаковка ограничена типами A и B .Почему невозможно создать экземпляр two () ?

template <typename T>
struct A {};

template <typename T>
struct B {};

template <typename... Ts>
void one(A<Ts> ...as) {
}

template <typename... Ts, typename... Us>
void two(A<Ts> ...as, B<Us> ...bs) {
}

int main() {
  auto a = A<int>();
  auto b = B<int>();

  // Just fine
  one();
  one(a);
  one(a, a);

  // All errors    
  two();
  two(a);
  two(a, b);
}

Пробовал с gcc и clang.

Ответы [ 3 ]

33 голосов
/ 08 октября 2012

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

#include <iostream>

template <typename... Types>
struct foo {};

template < typename... Types1, template <typename...> class T
         , typename... Types2, template <typename...> class V
         , typename U >
void
bar(const T<Types1...>&, const V<Types2...>&, const U& u)
{
  std::cout << sizeof...(Types1) << std::endl;
  std::cout << sizeof...(Types2) << std::endl;
  std::cout << u << std::endl;
}

int
main()
{
  foo<char, int, float> f1;
  foo<char, int> f2;
  bar(f1, f2, 9);
  return 0;
}
14 голосов
/ 23 марта 2012

Я нашел одно решение. Оберните каждый пакет параметров в кортеж. Используйте структуру для частичной специализации. Вот демонстрация, которая передает аргументы функтору, используя один кортеж в виде списка и накапливая другой. Ну, этот пересылает путем копирования. Кортежи используются при выводе типов, но никакие кортежи не используются в параметрах функций, что, я думаю, является правильным.

#include <iostream>
#include <tuple>

template < typename ... >
struct two_impl {};

// Base case
template < typename F,
           typename ...Bs >
struct two_impl < F, std::tuple <>, std::tuple< Bs... > >  {
  void operator()(F f, Bs... bs) {
    f(bs...);
  }
};

// Recursive case
template < typename F,
           typename A,
           typename ...As,
           typename ...Bs >
struct two_impl < F, std::tuple< A, As... >, std::tuple< Bs...> >  {
  void operator()(F f, A a, As... as, Bs... bs) {
    auto impl = two_impl < F, std::tuple < As... >, std::tuple < Bs..., A> >();
    impl(f, as..., bs..., a);
  }
};

template < typename F, typename ...Ts >
void two(F f, Ts ...ts) {
  auto impl = two_impl< F, std::tuple < Ts... >, std::tuple <> >();
  impl(f, ts...);
}

struct Test {
  void operator()(int i, float f, double d) {
    std::cout << i << std::endl << f << std::endl << d << std::endl;
  }
};

int main () {
  two(Test(), 1, 1.5f, 2.1);
}

Кортежи - очень хороший список времени компиляции.

6 голосов
/ 28 сентября 2018

Шаблоны функций (как пример skypjack) и частичные специализации шаблонов классов и переменных могут иметь несколько пакетов параметров, если каждый параметр шаблона, следующий за пакетом параметров шаблона, имеет значение по умолчанию или может быть выведен.Единственное, что я хотел бы добавить / указать, это то, что для шаблонов классов и переменных вам нужна частичная специализация.(См .: Шаблоны C ++, Полное руководство, Vandevoorde, Josuttis, Gregor 12.2.4, второе издание)

// A template to hold a parameter pack
template < typename... >
struct Typelist {};

// Declaration of a template
template< typename TypeListOne 
        , typename TypeListTwo
        > 
struct SomeStruct;

// Specialization of template with multiple parameter packs
template< typename... TypesOne 
        , typename... TypesTwo
        >
struct SomeStruct< Typelist < TypesOne... >
                 , Typelist < TypesTwo... >
                 >
{
        // Can use TypesOne... and TypesTwo... how ever
        // you want here. For example:
        typedef std::tuple< TypesOne... > TupleTypeOne;
        typedef std::tuple< TypesTwo... > TupleTypeTwo;
};      
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...