Каковы правила для токена " ... " в контексте вариативных шаблонов?
в 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 ответа:
в контексте вариативного шаблона, многоточие
...
используется для распаковки пакета параметров шаблона, если он отображается в правой части выражения (вызовите это выражение 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 {};
он находится в спецификации, но пока нет атрибута, который может быть выражен как тип.