C++11变参模板的参数包
来源:互联网 发布:单片机程序流程图画法 编辑:程序博客网 时间:2024/06/07 20:37
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 class template and in a function template 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 declarator, 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) pattern
s. Pattern must include at least one parameter pack.模板类型参数包和函数参数包,参数包解包,模板的偏特化是一种模式匹配,模板元则实际上是一种编译期的函数式编程。
Explanation
A variadic class template can be instantiated with any number of template arguments:
template<class ... Types> struct Tuple {};Tuple<> t0; // Types contains no argumentsTuple<int> t1; // Types contains one argument: intTuple<int, float> t2; // Types contains two arguments: int and floatTuple<0> error; // error: 0 is not a type
Reason: mention that it must be last in class template, but not function
A variadic function template can be called with any number of function arguments (the template arguments are deduced throughtemplate argument deduction):
template<class ... Types> void f(Types ... args);f(); // OK: args contains no argumentsf(1); // OK: args contains one argument: intf(2, 1.0); // OK: args contains two arguments: int and double
Pack expansion
A pattern followed by an ellipsis, in which the name of at least one parameter pack appears at least once, isexpanded into zero or more comma-separated instantiations of the pattern, where the name of the parameter pack is replaced by each of the types from the pack, in order.
//省略运算符紧接着一个模式,表示省略的部分可以展开为模式的一个或者多个用逗号隔开的实例。展开之后其实是一个用逗号分隔的列表的形式,这个列表可以作为模板和函数的参数,实参和形参都可以,或者用作为初始化列表,仅仅这些。而不能看做是一个逗号运算符构成的表达式!!!!!
template<class ...Us> void f(Us... pargs) {}template<class ...Ts> 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<typename...> struct Tuple {};template<typename T1, typename T2> struct Pair {}; template<class ...Args1> struct zip { template<class ...Args2> struct with { typedef Tuple<Pair<Args1, Args2>...> type;// Pair<Args1, Args2>... is the pack expansion// Pair<Args1, Args2> is the pattern };}; typedef zip<short, int>::with<unsigned short, unsigned>::type T1;// Pair<Args1, Args2>... expands to// Pair<short, unsigned short>, Pair<int, unsigned int> // T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>> typedef zip<short>::with<unsigned short, unsigned>::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<class ...Args> void g(Args... args) { f(const_cast<const Args*>(&args)...); // const_cast<const Args*>(&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 parantheses 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<const Args*>(&args)...);// f(const_cast<const E1*>(&X1), const_cast<const E2*>(&X2), const_cast<const E3*>(&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<class A, class B, class...C> void func(A arg1, B arg2, C...arg3){ container<A,B,C...> t1; // expands to container<A,B,E1,E2,E3> container<C...,A,B> t2; // expands to container<E1,E2,E3,A,B> container<A,C...,B> t3; // expands to container<A,E1,E2,E3,B> }
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<typename ...Ts> void f(Ts...) {}f('a', 1); // Ts... expands to void f(char, int)f(0.1); // Ts... expands to void f(double) template<typename ...Ts, int... N> void g(Ts (&...arr)[N]) {}int n[1];g<const char, int>("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:CWG #1488.
Template parameter list
Pack expansion may appear in a template parameter list:
template<typename... T> struct value_holder{ template<T... Values> // expands to a non-type template parameter struct apply { }; // list, such as <int, char, int(&)[5]>};
Base specifiers and member initializer lists
A pack expansion may designate the list of base classes in a class declaration. Typically, this also means that the constructor needs to use a pack expansion in themember initializer list to call the constructors of these bases:
template<class... Mixins>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 inlist-initialization and some other contexts), a pack expansion may appear as well:
template<typename... Ts> 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)] = { (std::cout << args, 0)... };}
Lambda captures
A parameter pack may appear in the capture clause of a lambda expression
template<class ...Args>void f(Args... args) { auto lm = [&, args...] { return g(args...); }; lm();}
The sizeof... operator
The sizeof... operator is classified as a pack expansion as well
template<class... Types>struct count { static const std::size_t value = sizeof...(Types);};
Dynamic exception specifications
The list of exceptions in a dynamic exception specification may also be a pack expansion
template<class...X> 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 keywordalignas
Attribute list
Pack expansions are allowed in the lists of attributes, as in [[attributes...]]. For example:void[[attributes...]] function()
Fold-expressions
In fold-expressions, the pattern is the entire subexpression that does not contain an unexpanded parameter pack.
(since C++17) This section is incompleteReason: a few words about partial specializations and other ways to access individual elements?
Example
#include <iostream> void tprintf(const char* format) // base function{ std::cout << format;} template<typename T, typename... Targs>void tprintf(const char* format, T value, Targs... Fargs) // recursive variadic function{ for ( ; *format != '\0'; format++ ) { if ( *format == '%' ) { std::cout << value; tprintf(format+1, Fargs...); // recursive call return; } std::cout << *format; }} int main(){ tprintf("% world% %\n","Hello",'!',123); return 0;}
Output:
Hello world! 123
The above example defines a function similar to std::printf, 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
function templateclass templatesizeof...Queries the number of elements in a parameter pack.C-style variadic functionsPreprocessor macrosCan be variadic as well- C++11变参模板的参数包
- 获取C++11 变参模板的参数数量
- c++11变参模板的展开
- 编译器对C++ 11变参模板(Variadic Template)的函数包扩展实现的差异
- c语言的变参数函数 柏贵林
- C++11变参模板
- C++11中的变参模板的使用
- c语言处理变参数变类型
- C变参的实现
- C变参的实现
- C语言的变参
- 学习变参模板
- C变参数函数demo
- C语言变参数函数
- C语言中可的变参数用法
- C语言变参数函数的原里
- c里面关于变参数函数的理解
- 混沌 IN C++::模板参数的奥秘
- 非递归学习树结构(四)--BST(二叉排序)树
- NAT介绍,防火墙介绍
- Light oj 1105 - Fi Binary Number(计数)
- java集合框架(上)
- LA 4329 - Ping pong(树状数组)
- C++11变参模板的参数包
- Linux Kernel CMPXCHG函数分析
- PMP之4 项目整合管理
- Pascal's Triangle
- 海尔称将开30000微店 家电巨头挖掘朋友圈商机
- 二叉搜索树
- scrollview嵌套listview
- 第三方框架
- CVBS