使用场景
模板参数可变化,下面这种是展开表达式
#include<iostream>
#include<bitset>
using namespace std;
void print() {}
template<typename T,typename... Types>
void print(const T& Arg, const Types&... args) {
cout<<Arg<<endl;
print(args...);
}
int main() {
print(7.5, "Hello World", bitset<16>(377), 42);
return 0;
}
该代码的第7行中template<typename T,typename... Types>
中第二个模板参数在typename后加...是是语法设计的一种,表示该参数可能有很多。比如该示例中的打印,print(const T& Arg, const Types&... args)
的实现中将Arg cout到屏幕上,然后再调用自己,并将args...
拆成新的Arg + args,循环往复,直到args...
为0个,调用print()
,结束递归。
下图是输出效果
另一种实现的方式是模板参数包
#include<iostream>
using namespace std;
template<typename... Types>
void print(Types... args) {
(cout << ... << args) << endl;
}
int main() {
print(1,2,3,"Hello World",5.5);
return 0;
}
原理
可变模板参数的原理是通过递归展开参数包来处理不同数量的参数。在递归展开的过程中,模板参数包中的每个参数都被单独处理,直到展开完所有参数。
相关知识点
编译时编译器对模板做了什么?(模板实例化)
编译器在编译时对模板进行了实例化,即将具体的数据类型替换模板设定的typename
模板实例化发生在什么时期
(涉及到编译的阶段)
模板实例化不是发生在预处理时期,而是发生在编译阶段的实例化时期,例如代码中创建对象或者调用函数时,编译器会传递给模板的具体类型生成实际的代码,这是懒惰的过程,只在需要的时候进行实例化,减少编译后可执行文件的大小