博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Parameter pack
阅读量:6023 次
发布时间:2019-06-20

本文共 10158 字,大约阅读时间需要 33 分钟。

Parameter pack

 
 
 
 

A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates). A function parameter pack is a function parameter that accepts zero or more function arguments.

A template with at least one parameter pack is called a variadic template.

Syntax

Template parameter pack (appears in a and in a parameter list)

 
type ... Args(optional) (1) (since C++11)
 
typename|class ... Args(optional) (2) (since C++11)
 
template < parameter-list > typename(C++17)|class ... Args(optional) (3) (since C++11)
 

Function parameter pack (a form of , appears in a function parameter list of a variadic function template)

 
Args ... args(optional) (4) (since C++11)
 

Parameter pack expansion (appears in a body of a variadic template)

 
pattern ... (5) (since C++11)
 
1) A non-type template parameter pack with an optional name
2) A type template parameter pack with an optional name
3) A template template parameter pack with an optional name
4) A function parameter pack with an optional name
5) Parameter pack expansion: expands to comma-separated list of zero or more patterns. Pattern must include at least one parameter pack.

Explanation

A variadic class template can be instantiated with any number of template arguments:

template
struct Tuple { }; Tuple<> t0; // Types contains no arguments Tuple
t1; // Types contains one argument: int Tuple
t2; // Types contains two arguments: int and float Tuple<0> error; // error: 0 is not a type

A variadic function template can be called with any number of function arguments (the template arguments are deduced through ):

template
void f(Types ... args); f(); // OK: args contains no arguments f(1); // OK: args contains one argument: int f(2, 1.0); // OK: args contains two arguments: int and double

In a primary class template, the template parameter pack must be the final parameter in the template parameter list. In a function template, the template parameter pack may appear earlier in the list provided that all following parameters can be deduced from the function arguments, or have default arguments:

template
struct Invalid; // Ts.. not at the end template
void invalid(); // U not deduced //U deduced, anonymous parameter defaulted template
void valid(Ts..., U);

Pack expansion

A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, is expanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the elements from the pack, in order.

template
void f(Us... pargs) { } template
void g(Ts... args) { f(&args...); // “&args...” is a pack expansion // “&args” is its pattern } g(1, 0.2, "a"); // Ts... args expand to int E1, double E2, const char* E3 // &args... expands to &E1, &E2, &E3 // Us... pargs expand to int* E1, double* E2, const char** E3

If the names of two parameter packs appear in the same pattern, they are expanded simultaneously, and they must have the same length:

template
struct Tuple { }; template
struct Pair { }; template
struct zip { template
struct with { typedef Tuple
...> type; // Pair
... is the pack expansion // Pair
is the pattern }; }; typedef zip
::with
::type T1; // Pair
... expands to // Pair
, Pair
// T1 is Tuple
, Pair
> typedef zip
::with
::type T2; // error: pack expansion contains parameter packs of different lengths

If a pack expansion is nested within another pack expansion, the parameter packs that appear inside the innermost pack expansion are expanded by it, and there must be another pack mentioned in the enclosing pack expansion, but not in the innermost one:

template
void g(Args... args) { f(const_cast
(&args)...); // const_cast
(&args) is the pattern, it expands two packs // (Args and args) simultaneously f(h(args...) + args...); // Nested pack expansion: // inner pack expansion is "args...", it is expanded first // outer pack expansion is h(E1, E2, E3) + args..., it is expanded // second (as h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3) }

Expansion loci

Depending on where the expansion takes place, the resulting comma-separated list is a different kind of list: function parameter list, member initializer list, attribute list, etc. The following is the list of all allowed contexts

Function argument lists

A pack expansion may appear inside the parentheses of a function call operator, in which case the largest expression to the left of the ellipsis is the pattern that is expanded.

f(&args...); // expands to f(&E1, &E2, &E3)f(n, ++args...); // expands to f(n, ++E1, ++E2, ++E3); f(++args..., n); // expands to f(++E1, ++E2, ++E3, n); f(const_cast
(&args)...); // f(const_cast
(&X1), const_cast
(&X2), const_cast
(&X3)) f(h(args...) + args...); // expands to // f(h(E1,E2,E3) + E1, h(E1,E2,E3) + E2, h(E1,E2,E3) + E3)

Template argument lists

Pack expansions can be used anywhere in a template argument list, provided the template has the parameters to match the expansion.

template
void func(A arg1, B arg2, C...arg3) { container
t1; // expands to container
container
t2; // expands to container
container
t3; // expands to container
}

Function parameter list

In a function parameter list, if an ellipsis appears in a parameter declaration (whether it names a function parameter pack (as in, Args ... args) or not) the parameter declaration is the pattern:

template
void f(Ts...) { } f('a', 1); // Ts... expands to void f(char, int) f(0.1); // Ts... expands to void f(double) template
void g(Ts (&...arr)[N]) { } int n[1]; g
("a", n); // Ts (&...arr)[N] expands to // const char (&)[2], int(&)[1]

Note: In the pattern Ts (&...arr)[N], the ellipsis is the innermost element, not the last element as in all other pack expansions.

Note: Ts (&...)[N] is not allowed because the C++11 grammar requires the parenthesized ellipsis to have a name: .

Template parameter list

Pack expansion may appear in a template parameter list:

template
struct value_holder { template
// expands to a non-type template parameter struct apply { }; // list, such as
};

Base specifiers and member initializer lists

A pack expansion may designate the list of base classes in a . Typically, this also means that the constructor needs to use a pack expansion in the to call the constructors of these bases:

template
class X : public Mixins... { public: X(const Mixins&... mixins) : Mixins(mixins)... { } };

Braced init lists

In a braced-init-list (brace-enclosed list of initializers and other braced-init-lists, used in and some other contexts), a pack expansion may appear as well:

template
void func(Ts... args){ const int size = sizeof...(args) + 2; int res[size] = { 1,args...,2}; // since initializer lists guarantee sequencing, this can be used to // call a function on each element of a pack, in order: int dummy[sizeof...(Ts)] = { ( << args, 0)... }; }

Lambda captures

A parameter pack may appear in the capture clause of a expression

template
void f(Args... args) { auto lm = [&, args...] { return g(args...); }; lm(); }

The sizeof... operator

The operator is classified as a pack expansion as well

template
struct count { static const value = sizeof...(Types); };

Dynamic exception specifications

The list of exceptions in a may also be a pack expansion

template
void func(int arg) throw(X...) { // ... throw different Xs in different situations }

Alignment specifier

Pack expansions are allowed in both the lists of types and the lists of expressions used by the keyword

Attribute list

Pack expansions are allowed in the lists of , as in [[attributes...]]. For example: void [[attributes...]] function()

Fold-expressions

In , the pattern is the entire subexpression that does not contain an unexpanded parameter pack.

Using-declarations

In , ellipsis may appear in the list of declarators, this is useful when deriving from a parameter pack:

template 
struct X : bases... { using bases::g...; }; X
x; // OK: B::g and D::g introduced
(since C++17)

Notes

Example

#include 
 void tprintf(const char* format) // base function { << format; } template
void tprintf(const char* format, T value, Targs... Fargs) // recursive variadic function { for ( ; *format != '\0'; format++ ) { if ( *format == '%' ) { << value; tprintf(format+1, Fargs...); // recursive call return; } << *format; } } int main() { tprintf("% world% %\n","Hello",'!',123); return 0; }

Output:

Hello world! 123

The above example defines a function similar to , that replace each occurrence of the character % in the format string with a value.

The first overload is called when only the format string is passed and there is no parameter expansion.

The second overload contains a separate template parameter for the head of the arguments and a parameter pack, this allows the recursive call to pass only the tail of the parameters until it becomes empty.

Targs is the template parameter pack and Fargs is the function parameter pack

See also

Queries the number of elements in a parameter pack.
Can be variadic as well

转载地址:http://lrjqx.baihongyu.com/

你可能感兴趣的文章
异步调用方法总结
查看>>
.Net 夯实基础
查看>>
IB Fix开发 之 Quickfix 解读
查看>>
(转载)《80后出师表》
查看>>
mysql分组排序取最大值所在行,类似hive中row_number() over partition by
查看>>
ubuntu10.10下编译android 2.3遇到的错误及解决方法
查看>>
理解 ARC 下的循环引用
查看>>
eclipse中jdk源码调试步骤
查看>>
Spring MVC中,事务是否可以加在Controller层
查看>>
Python用format格式化字符串
查看>>
10款设计师必备的响应式网页设计工具
查看>>
关于直线,折线切割平面的问题
查看>>
从ICLassFactory 为 CLSID的COM组建创建实例失败:c001f011
查看>>
Apache在windows下的安装
查看>>
MD5加密算法(实际应用)
查看>>
Luogu P3275 糖果
查看>>
Django view 视图
查看>>
【转载】获得当前的视图设置
查看>>
Li Fei-fei写给她学生的一封信,如何做好研究以及写好PAPER(转载)
查看>>
1052. 卖个萌 (20)
查看>>