赞
踩
可变参数模板是C++11引入的特性,它能够创建可变数量参数的模板函数和模板类。这一特性让我们可以编写出更加灵活和通用的代码。
可能光这样子说,没有感觉,那就举一个简单的例子吧,假设现在有一个需求:
要编写一个函数,它可以接收任意数量的参数,并且参数类型只需要是cout能够显示的即可。
从需求来看,传进函数的参数数量不固定,并且类型的顺序也不固定,我们不可能定义很多个打印函数来做到这个需求,因为组合的情况太多太多了。
这种情况下,用可变参数模板就可以解决这个问题。在后面的部分,我将用上面这个例子贯穿全文来说明可变参数模板,旨在说明可变参数模板这个技术。
C++11提供了一个用省略号(...)表示的元运算符,用这个运算符来表示模板参数包和函数参数包的标识符,模板参数包基本上是一个类型列表,函数参数包基本上是一个值列表,语法如下:
模板参数包Args与任意数量(包括零)的类型匹配,函数参数包args所包含的值列表与模板参数包所含的类型列表(无论是类型还是数量)匹配。
上面那个打印函数参数的那个例子,我们可以声明为如下这样:
- template<typename... Args>
- void show_list(Args... args) {
-
- ......
-
- }
如果现在我们需要这样调用它:
show_list('I', "love", 2024);
那模板参数包和函数参数包的内容该如何访问呢?索引功能在这里无法使用,即不能使用类似于Args[1]来访问包中的第二个参数类型;
函数参数包的话,可以将省略号放在其右边(即:args...),将参数包展开。采用递归的方式访问:对参数列表里的第一项进行处理,再将余下的内容传递给递归调用,直到列表为空。
还是关于打印参数这个例子,看一下如何展开这个函数参数包并打印。和常规递归一样,确保递归终止很重要, 最后写出来的代码如下:
- // 递归终止条件
- void show_list() {};
-
- template<typename T, typename... Args>
- void show_list(T value, Args... args) {
- // 打印第一个参数,然后递归打印剩余参数
- cout << value << " ";
- show_list(args...);
- };
-
- void test01() {
- show_list('I', "love", 2024);
- return;
- };
在上面的示例中,show_list
函数使用了可变参数模板。当调用show_list
函数时,它会递归地打印每个参数,直到没有剩余参数为止。 这里有一个技巧就是函数模板的头改为了:
- template<typename T, typename... Args>
- void show_list(T value, Args... args) {}
show_list()的第一个实参决定了T和value的值,而其他实参决定了Args和args的值。这让函数能够对value进行处理;然后递归调用show_list(),并以args...的方式将其他实参传递给它。每一次递归调用处理一个值,并且传递缩短了的列表,直到列表为空为止:
最后函数调用过程就如下面这张图所示
折叠表达式展开的方式是到了C++ 17才提供的,C++ 11是不支援的。折叠表达式示例如下:
- template<typename... Args>
- void show_list(const Args&... args) {
- (cout << ... << args)<<endl;
- };
但是打印时各个参数都粘在了一起,不好看。可以利用逗号表达式控制一下格式打印,如下所示:
- template<typename... Args>
- void show_list(const Args&... args) {
- (cout << ... << (cout<<args," ")) << endl;
- };
还有其他的展开参数包的方式,不过这里就不多做介绍了,可以参考其他的博客:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。