Parameter pack
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 arguments
- Tuple<int> t1; // Types contains one argument: int
- Tuple<int, float> 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 argument deduction):
- template<class ... Types> 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<typename... Ts, typename U> struct Invalid; // Ts.. not at the end
- template<typename... Ts, typename U> void invalid(); // U not deduced
- //U deduced, anonymous parameter defaulted
- template<typename ...Ts, typename U, typename=void>
- 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<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 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<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 the member 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 in list-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 keyword alignas
Attribute list
Pack expansions are allowed in the lists of attributes, as in [[attributes...]]. For example: void [[attributes...]] function()
Fold-expressionsIn fold-expressions, the pattern is the entire subexpression that does not contain an unexpanded parameter pack. Using-declarationsIn using declaration, ellipsis may appear in the list of declarators, this is useful when deriving from a parameter pack:
|
(since C++17) |
Notes
This section is incomplete Reason: a few words about partial specializations and other ways to access individual elements? Mention recursion vs logarithmic vs shortcuts such as fold expressions |
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 template | |
class template | |
sizeof... | Queries the number of elements in a parameter pack. |
C-style variadic functions | |
Preprocessor macros | Can be variadic as well |
Parameter pack的更多相关文章
- C++14使用std::integer_sequence展开tuple作为函数的参数
元组是一种长度固定的允许有不同类型元素的集合,根据元素的个数不同又分别称作一元组.二元组.三元组等.C++11中标准库增加了一个叫std::tuple的类模板,用于表示元组. 下面的代码演示了使用C+ ...
- C++11变长参数模板
[C++11变长参数模板] C++03只有固定模板参数.C++11 加入新的表示法,允许任意个数.任意类别的模板参数,不必在定义时将参数的个数固定. 实参的个数也可以是 0,所以 tuple<& ...
- Objects
Obeject Object Object representation and value representation Subobjects Polyomrphic objecets Alignm ...
- “Clang” CFE Internals Manual---中文版---"Clang"C语言前端内部手册
原文地址:http://clang.llvm.org/docs/InternalsManual.html 译者:史宁宁(snsn1984) "Clang"C语言前端内部手册 简介 ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- C++ 变长模板参数
转载自: http://www.cnblogs.com/liyiwen/archive/2013/04/13/3018608.html C++11 语言核心的改进中,最为关注的有 rvalue ref ...
- 深入理解C++11【4】
[深入理解C++11[4]] 1.基于范围的 for 循环 C++98 中需要告诉编译器循环体界面范围.如for,或stl 中的for_each: int main() { ] = { , , , , ...
- 介绍C++11标准的变长参数模板
目前大部分主流编译器的最新版本均支持了C++11标准(官方名为ISO/IEC14882:2011)大部分的语法特性,其中比较难理解的新语法特性可能要属变长参数模板(variadic template) ...
- 使用 C++11 编写类似 QT 的信号槽——上篇
了解 QT 的应该知道,QT 有一个信号槽 Singla-Slot 这样的东西.信号槽是 QT 的核心机制,用来替代函数指针,将不相关的对象绑定在一起,实现对象间的通信. 考虑为 Simple2D 添 ...
随机推荐
- C# 实现动态添加列,新增合计行,求和
DataTable da = CommonBLL.GetList("*", "sys_dict", "IfState=1 and DictTypeId ...
- 【转载】Python,使用Wheel打包
转载自: http://blog.sina.com.cn/s/blog_1318255b00102wbtz.html Python的第一个主流打包格式是.egg文件,现在大家庭中又有了一个叫做Whee ...
- Qt笔记——QSqlLite
静态数据库,简单方便 在.pro文件里添加 +sql #ifndef WIDGET_H #define WIDGET_H #include <QWidget> namespace Ui { ...
- 【机器学习】k-近邻算法应用之手写数字识别
上篇文章简要介绍了k-近邻算法的算法原理以及一个简单的例子,今天再向大家介绍一个简单的应用,因为使用的原理大体差不多,就没有没有过多的解释. 为了具有说明性,把手写数字的图像转换为txt文件,如下图所 ...
- Jenkins+maven+Tomcat配置发布
jenkins大多数情况下都是用来部署Java项目,Java项目有一个特点是需要编译和打包的,一般情况下编译和打包都是用maven完成,所以系统环境中需要安装maven. 实验环境: 10.0.0.1 ...
- BotFramework Nodejs示例
关于Bot Framework知识,可以参考<Nodejs Bot学习> 本文是根据bot framework sample<https://github.com/Microsoft ...
- apache 把404页面的url转发给php脚本处理
# .htaccess1 RewriteCond %{REQUEST_FILENAME} !-f 2 RewriteRule ^(.*)$ map.php?host=%{HTTP_HOST}& ...
- 洛谷P1197 [JSOI2008] 星球大战 [并查集]
题目传送门 星球大战 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这 ...
- JavaWeb中常见的乱码处理(亲测)
常见编码方式: ISO-8859-1 西欧码 GB2312 简体中文码 GBK 大五码 UTF-8 全球码(推荐) 1.页面(HTML,JSP,Servlet) <%@ page lan ...
- 洛谷——P1208 [USACO1.3]混合牛奶 Mixing Milk
P1208 [USACO1.3]混合牛奶 Mixing Milk 题目描述 由于乳制品产业利润很低,所以降低原材料(牛奶)价格就变得十分重要.帮助Marry乳业找到最优的牛奶采购方案. Marry乳业 ...