template<typename... T> 可变模板参数
cppreference解释地址。
模板参数包在模板参数中的顺序要求:
在主类模板中,模板参数包必须是模板参数列表中的最后一个参数。
在函数模板中,模板参数包可能出现在列表的前面,前提是以下所有参数都可以从函数参数中推导出来,或者具有默认参数:
template < typename U, typename ... Ts > // OK: 可以推断 U
struct valid ;
// template<typename... Ts, typename U> // 错误:Ts... 不在最后
// struct Invalid;
template < typename ... Ts , typename U, typename = void >
void valid ( U, Ts... ) ; // OK:可以推导出 U
// void valid(Ts..., U); // 不能使用:Ts... 是这个位置的非推导上下文
valid ( 1.0 , 1, 2 , 3 ) ; // OK:将 U 推导为 double,将 Ts 推导为 {int, int, int}
pack expansion模板参数包扩展
情况一:参数包作为参数传入另一个带有可变模板参数的模板中
被扩展为零个或多个以逗号分隔的模式实例,其中参数包的名称从包中按顺序被每个元素替换
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
情况二:如果两个参数包的名称以相同的模式出现,则它们被同时扩展,并且它们必须具有相同的长度:
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
情况三:如果包扩展嵌套在另一个包扩展中
则出现在最里面的包扩展中的参数包由它扩展,并且必须在封闭的包扩展中提到另一个包,但不在最里面的包中:
template < class ... Args >
void g ( Args ... args )
{
f ( const_cast < const Args * > ( & args ) ... ) ;
// const_cast<const Args*>(&args) 是模式,它同时扩展两个包 // (Args 和 args)
f ( h ( args... ) + args... ) ; // 嵌套包扩展:
// 内包扩展是“args...”,它首先被扩展
// outer pack expansion is h(E1, E2, E3) + args..., 它被扩展
// second (as h(E1, E2, E3) + E1, h(E1, E2, E3) + E2, h(E1, E2, E3) + E3)
}
在完美转发时也会用到该模板参数包:同时扩展类型和实参
template<typename... ParamT>
f(ParamT... param){
f2(std::forward<ParamT>(param)...);
}
扩展位点
- 函数参数列表
- 带括号的初始值设定项
- 模板参数列表
- Lambda 捕获
- sizeof...运算符
- 动态异常规范
- ....