Каковы правила для токена " ... " в контексте вариативных шаблонов?


в C++11 есть вариативные шаблоны, такие как этот:

template< class T, class... Args >
unique_ptr<T> make_unique( Args&&... args )
{
    return unique_ptr<T>(new T(std::forward<Args>(args)...));
}

есть некоторые курьезы об этом: выражение std::forward<Args>(args)... использует Args и args но только один ... маркер. Кроме того std::forward - это не вариативная функция шаблона, принимающая только один параметр шаблона и один аргумент. Каковы синтаксические правила для этого (грубо)? Как его можно обобщить?

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

2 91

2 ответа:

в контексте вариативного шаблона, многоточие ... используется для распаковки пакета параметров шаблона, если он отображается в правой части выражения (вызовите это выражение pattern на мгновение). Правило таково, что бы ни pattern находится на левой стороне ... повторяется-распакованные шаблоны (назовите их выражения теперь) разделяются запятой ,.

это лучше всего можно понять на некоторых примерах. Предполагать у вас есть этот шаблон функции:

template<typename ...T>
void f(T ... args) 
{
   g( args... );        //pattern = args
   h( x(args)... );     //pattern = x(args)
   m( y(args...) );     //pattern = args (as argument to y())
   n( z<T>(args)... );  //pattern = z<T>(args)
}

теперь, если я вызываю эту функцию передачи T как {int, char, short}, затем каждый вызов функции расширяется как:

g( arg0, arg1, arg2 );           
h( x(arg0), x(arg1), x(arg2) );
m( y(arg0, arg1, arg2) );
n( z<int>(arg0), z<char>(arg1), z<short>(arg2) );

в коде, который вы разместили,std::forward следует четвертому шаблону, проиллюстрированному n() вызов функции.

обратите внимание на разницу между x(args)... и y(args...) выше!


можно использовать ... для инициализации массива, также как:

struct data_info
{
     boost::any  data;
     std::size_t type_size;
};

std::vector<data_info> v{{args, sizeof(T)}...}; //pattern = {args, sizeof(T)}

который расширяется до этого:

std::vector<data_info> v 
{ 
   {arg0, sizeof(int)},
   {arg1, sizeof(char)},
   {arg2, sizeof(short)}
};

я только что понял, что шаблон может даже включать спецификатор доступа, такой как public, как показано в следующем примере:

template<typename ... Mixins>
struct mixture : public Mixins ...  //pattern = public Mixins
{
    //code
};

в этом примере шаблон расширяется следующим образом:

struct mixture__instantiated : public Mixin0, public Mixin1, .. public MixinN  

то есть mixture выводит публично из всех базовых классов.

надеюсь, что это поможет.

следующее взято из разговора "шаблоны с переменным числом аргументов является Funadic" Андрей Александреску на GoingNative 2012. Я могу рекомендовать его для хорошего введения в вариативные шаблоны.


есть две вещи, которые можно сделать с вариативным пакет. Это можно применить sizeof...(vs) чтобы получить количество элементов и развернуть его.

правила расширения

Use            Expansion

Ts...          T1, ..., Tn
Ts&&...        T1&&, ..., Tn&&
x<Ts,Y>::z...  x<T1,Y>::z, ..., x<Tn,Y>::z
x<Ts&,Us>...   x<T1&,U1>, ..., x<Tn&,Un>
func(5,vs)...  func(5,v1), ..., func(5,vn)

расширение продолжается внутрь наружу. При расширении двух списков в замок-шаг, они должны иметь одинаковый размер.

примеры:

gun(A<Ts...>::hun(vs)...);

расширяет все Ts в списке аргументов шаблона A а потом функция hun расширяется со все vs.

gun(A<Ts...>::hun(vs...));

расширяет все Ts в списке аргументов шаблона A и vs в качестве аргументов функции hun.

gun(A<Ts>::hun(vs)...);

расширяет функции hun С Ts и vs in стоп-шаг.

Примечание:

Ts - это не тип, а vs - это не ценность! Они являются псевдонимами для списка типов / значений. Любой список может быть потенциально пустым. Оба подчиняются только определенным действиям. Так как не представляется возможным:

typedef Ts MyList;  // error!
Ts var;             // error!
auto copy = vs;     // error!

локусов расширения

аргументов функции

template <typename... Ts>
void fun(Ts... vs)

списки инициализатора

any a[] = { vs... };

база спецификаторы

template <typename... Ts>
struct C : Ts... {};
template <typename... Ts>
struct D : Box<Ts>... { /**/ };

инициализатора списки

// Inside struct D
template <typename... Us>
D(Us... vs) : Box<Ts>(vs)... {}

список аргументов шаблона

std::map<Ts...> m;

будет компилироваться только в том случае, если есть возможное совпадение для Аргументов.

списки захват

template <class... Ts> void fun(Ts... vs) {
    auto g = [&vs...] { return gun(vs...); }
    g();
}

списки атрибутов

struct [[ Ts... ]] IAmFromTheFuture {};

он находится в спецификации, но пока нет атрибута, который может быть выражен как тип.