前言:
c++ 11 引入和变参模板用来处理任意数量模板参数的场景。
变参模板函数 (C++11/14 迭代展开 | 一个模板参数和一个模板参数包)
#include <iostream>
#include <string>void MyPrint(){std::cout << " end" << std::endl;
}template<typename FirstArgInArgs, typename... Args>
void MyPrint(FirstArgInArgs first,Args... following)
{std::cout << first << "|" ;MyPrint(following...);
}int main()
{MyPrint<std::string,int,int,long,char,double>("let's start",1,2,10000,'K',3.14);
}
运行结果
let's start|1|2|10000|K|3.14| end
需要注意的几点:
- 变参模板中,不能只有模板参数包(列表) Args,必须要包含一个模板参数(FirstArgInArgs)在模板参数包(Args)之前,否则会编译不通过。
- C++ 11/14只能使用递归的方式展开模板参数包(列表),由于使用了递归,因此需要一个递归终结条件 —— “终止函数”,当参数包长度为0的时候,这个终止函数被调用,形式为模板函数的无参数版本,比如 例子中的 void MyPrint()。这个函数必须要有且要在模板参数前面定义或提前声明。
- 使用 C++ 11/14 的递归方式展开参数包时,第一个模板参数 FirstArgInArgs 用来在递归场景下接收参数包里的第一个参数,以例子来说明,递归逻辑如下
- 第一次调用 MyPrint<std::string,...>("let's start",following...) , 这里 FirstArgInArgs 用来接收 let's start 这个 string 类型。这个时候通过 std::cout << first << "|" 输出了 let's start 。这里需要注意,FirstArgInArgs 并不会被当作一个特殊的参数用来接收 let's start,而是因为其在Args之前,故而被用来为 FirstArgInArgs 服务。
- 第二次调用 MyPrint<int,...>(1,following...),这里 FirstArgInArgs 用来接收 int , 所以 1 被输出了。
- 第三次,第四次同理...
变参模板函数 ( C++11/14 迭代展开 | 一个固定模板参数,一个模板参数用于解包,一个模板参数包 (gstreamer里面可以用来编写 add 和 link 函数))
#include <iostream>
#include <string>template<typename element>
void MyPrint(element e)
{std::cout << "1st-" << e << std::endl;
}template<typename pipeline, typename element, typename... elementlist>
void MyPrint(pipeline p,element e,elementlist... list)
{std::cout << "2nd-" << p << std::endl;MyPrint(e,list...);
}int main()
{MyPrint<std::string,std::string,std::string,std::string,std::string,std::string>("pipeline","appsrc","filter1","filter2","filter3","appsink");
}
运行结果
2nd-pipeline
2nd-appsrc
2nd-filter1
2nd-filter2
2nd-filter3
1st-appsink
单参数模板是通用模板void MyPrint(element e),也是迭代退出的“终止函数”, 可以看到和上章节z中以无参数版本 void MyPrint() 作为 “终止函数” 不同,这里的终止函数是 有一个参数的。那么为什么有这个差别呢?
蹊跷就在于模板函数里迭代调用的那个函数,这里是 MyPrint(e,list...) ,当 list... 为空的时候,MyPrint(e,list...) 就变成了 MyPrint(e), 这恰恰就是只有一个参数的MyPrint版本。
而上一章中的 模板函数是 MyPrint(following...) , 当 following... 是空的时候, MyPrint(following...) 就蜕变成 MyPrint()了。
所以在写终止函数的时候要根据模板函数的迭代函数形式来写,不然会出现没有终止函数的情况。