https://www.cnblogs.com/my_life/articles/8950031.html
https://blog.csdn.net/zhouguoqionghai/article/details/48661523
http://en.cppreference.com/w/cpp/language/parameter_pack
http://www.cnblogs.com/my_life/articles/8961332.html 介绍了类型、非类型模版参数
http://en.cppreference.com/w/cpp/language/parameter_pack
http://zh.cppreference.com/w/cpp/language/parameter_pack
http://www.cnblogs.com/liyiwen/archive/2013/04/13/3018608.html 解包
template <class... T> void f(T... args);
上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。
/* typename... Args定义可变模板参数 */
/* Args... args展开模板参数 定义函数形参 *//* args...展开函数实参 */template<typename Function, typename... Args> void call(Function fun, Args... args){ fun(args...);}
在C++11之前, 类模板和函数模板只能含有固定数量的模板参数, 在C++11之后的新特性可变模板参数允许包含0到任意个模板参数. 声明可变模板参数时需要在typename和class后面带上省略号'...'.
一个可变参数类模板定义如下:
template<typename ... Types> //这是类型模版参数,模版参数必须是类型
class Tuple
{};
可以用任意数量的类型来实例化Tuple:
Tuple<> t0;
Tuple<int> t1;
Tuple<int, string> t2;
// Tuple<0> error; 0 is not a type //template<typename ... Types> ,这是类型模版参数,模版参数必须是类型,0是非类型
如果想避免出现用0个模板参数来实例化可变参数模板,可以这样定义模板:
template<typename T, typename ... Types>
class Tuple
{};
此时在实例化时,必须传入至少一个模板参数,否则无法编译。
同样地,可以定义接收任意参数的可变参数函数模板:
template<typename ... Types>
void f(Types ... args);
// 一些合法的调用
f();
f(1);
f(3.4, "hello");
======================================================================
模版参数包也是分非类型参数包和类型参数包两种情况的:
type ... name(optional) (3) (since C++11) //非类型模版参数; 是固定的int,string等固定的类型
A non-type template parameter pack with an optional name. (非类型参数包) 类型固定,参数不固定
例如: template <int N, int... Rest> 暂没找到好的例子
typename|class ... name(optional) (since C++11) //类型模版参数;
A type template parameter pack with an optional name. (类型参数包),类型不固定
A template parameter pack is a template parameter that accepts zero or more template arguments (non-types, types, or templates).
模版参数包本质上就是一个模版参数,只不过该模版参数可以接收0个或者多个模版实参(例如非类型,类型,模版)
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( 可变参数模板 ; 可变模板 ; 变长参数模板 ; 变参模板).
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<int>(1)
http://www.cnblogs.com/my_life/articles/5165974.html
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; // Error: Ts.. not at the end //类模版中,可变参数包必须放最后
template<typename ...Ts, typename U, typename=void>
void valid(U, Ts...); // OK: can deduce U
// void valid(Ts..., U); // Can't be used: Ts... is a non-deduced context in this position
valid(1.0, 1, 2, 3); // OK: deduces U as double, Ts as {int,int,int}
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) { //class ...Ts 是可变模版非类型参数;
f(&args...); // “args...” is a pack expansion; args...是包展开; &再取他们的地址
// “&args” is its pattern; &args是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:
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 parameter list 函数形参
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> //typename ...Ts 模版非类型可变参数包, int... N模版类型可变参数包; 可变的Ts和N的元素是一一对应的; T1[N1], T2[N2], T3[N3]....
void g(Ts (&...arr)[N]) {
}
int n[1];
g<const char, int>("a", n); // Ts (&...arr)[N] expands to
// const char (&)[2], int(&)[1]
https://www.cnblogs.com/my_life/articles/4076180.html
数组的指针: int (*arr)[4];
数组的引用: int (&arr)[4];
指向数组的指针: int* arr_p[4];
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.
Ts (&...)[N] 这种格式在C++11中不运行,需要一个name, Ts (&...arr_name)[N]
-
Function argument lists 函数实参
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)
-
Parenthesized initializers 圆括号的初始化
Class c1(&args...); // calls Class::Class(&E1, &E2, &E3)
Class c2 = Class(n, ++args...); // calls Class::Class(n, ++E1, ++E2, ++E3);
::new((void *)p) U(std::forward<Args>(args)...) // std::allocator::allocate
-
Brace-enclosed initializers 花括号的初始化列表
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)... }; 带逗号表达式的花括号初始化列表
}
https://www.cnblogs.com/my_life/articles/8950031.html
我们知道逗号表达式会按顺序执行逗号前面的表达式,比如:
d = (a = b, c);
这个表达式会按顺序执行:b会先赋值给a,接着括号中的逗号表达式返回c的值,因此d将等于c。
-
Template argument lists 模版实参
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>
}
-
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 基类指定符与成员初始化列表
template<class... Mixins>
class X : public Mixins... {
public:
X(const Mixins&... mixins) : Mixins(mixins)... { }
};
-
Lambda captures Lambda 捕获
template<class ...Args>
void f(Args... args) {
auto lm = [&, args...] { return g(args...); };
lm();
}
-
The sizeof... operator sizeof... 运算符
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 动态异常规定中的异常列表亦可为包展开
-
Alignment specifier 对齐指定符
-
Attribute list 属性列表
-
Fold-expressions 折叠表达式
-
Using-declarations using 声明
在 using 声明中,省略号可以出现于声明器列表内,这对于从参数包导出有用:
template <typename... bases>
struct X : bases... {
using bases::g...;
};
X<B, D> x; // OK :引入 B::g 与 D::g
浙公网安备 33010602011771号