做个小笔记
Template parameter pack(模板参数包)是C++中用于接受零个或多个模板参数的一种机制。
语法:typename|class... pack-name
示例:模板参数只有一个参数包的情况
-
这个例子演示了一个可变参数的类模板(variadic class template)的定义和实例化。类模板名为Tuple,使用了模板参数包Types,该模板参数包表示可以接受零个或多个类型参数。
template<class... Types> struct Tuple { };Tuple<> t0; Tuple<int> t1; Tuple<int, float> t2; Tuple<0> t3; // error, 0 不是一个类型
-
同样的,可变参数函数模板可以使用任意数量的函数参数进行调用,0个或多个,并且类型可自动推导
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
示例:模板参数为1个参数包+N个参数
类模板和函数模板是不同的,类模板的模板参数并不能自动推导,因为实例化一个模板类没有形参可以参考,因此分开讨论
类模板的参数包必须出现在最后:在类模板的声明中,如果模板参数包在前面,编译器无法正确地确定模板参数包的结束位置
- 合法:
template<typename U, typename... Ts> struct MyClass {/**/};MyClass<int, double, double> myClass; // 很明确,U为int, 参数包包含两个Double
- 非法:参数包Ts没有在最后
template<typename... Ts, typename U> struct MyClass {/**/};MyClass<int, double, double> myClass; // 不够明确!可以认为这三个都是参数包Ts的参数,而U的类型没给
函数模板的参数包依然建议放在最后面,但也可以出现在参数列表的前面,但必须在模板函数的形参中把参数包放在最后面。
- 合法:
template<typename... Ts, typename U> void func(U u, Ts... args); func(5, 2.0, "uuu"); // U为int, 参数包为(double, const char*)
- 非法:无法确定参数包的结束位置
template<typename... Ts, typename U = int> void func(Ts... args, U u);
参数包展开
语法:如void func(Ts... args);
Ts
是一个模板参数包,表示一组类型。
args
是函数参数包,表示一组函数参数。
举例:
template<class... Us>
void f(Us... pargs) // 形参自动展开成指针变量
{/**/
}template<class... Ts>
void g(Ts... args)
{f(&args...); // 地址传递
}
g(1, 0.2, "a"); // 值传递
Ts... args
展开为:int E1, double E2, const char* E3
&args...
展开为:&E1, &E2, &E3
Us... pargs
展开为:int* E1, double* E2, const char** E3
到此为止。。简单使用,能看懂一部分源码了。
后面部分,比较难懂,比如文档中提到的 模式(pattern) 的概念非常重要,直接看文档吧:cppreference:https://en.cppreference.com/w/cpp/language/parameter_pack