c++ 可变参数模板展开原理
来源:互联网 发布:逆战网络迟 编辑:程序博客网 时间:2024/06/05 06:56
原文链接:http://www.cnblogs.com/chengyuanchun/p/5757823.html
例子内容出自:祁宇《深入应用C++11代码游湖与工程级应用》
1.概述
C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数、任意类型的参数。相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以它也是C++11中最难理解和掌握的特性之一。
虽然掌握可变模版参数有一定难度,但是它却是C++11中最有意思的一个特性,本文希望带领读者由浅入深的认识和掌握这一特性,同时也会通过一些实例来展示可变参数模版的一些用法。
2.可变模版参数的展开
可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号“...”。比如我们常常这样声明一个可变模版参数:template<typename...>或者template<class...>,一个典型的可变模版参数的定义是这样的:
template<typename... T> void fun(T... args) { }
上面的可变模版参数的定义当中,省略号的作用有两个:
1.声明一个参数包T... args,这个参数包中可以包含0到任意个模板参数;
2.在模板定义的右边,可以将参数包展开成一个一个独立的参数。
上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。
可变模版参数和普通的模版参数语义是一致的,所以可以应用于函数和类,即可变模版参数函数和可变模版参数类,然而,模版函数不支持偏特化,所以可变模版参数函数和可变模版参数类展开可变模版参数的方法还不尽相同,下面我们来分别看看他们展开可变模版参数的方法。
3.可变模板参数函数
一个简单的可变模版参数函数:
template<typename... T>void fun(T... args){ // 打印参数个数 cout << sizeof...(args) << endl; }
上面的例子中,fun()没有传入参数,所以参数包为空,输出的size为0,后面两次调用分别传入两个和三个参数,故输出的size分别为2和3。由于可变模版参数的类型和个数是不固定的,所以我们可以传任意类型和个数的参数给函数f。这个例子只是简单的将可变模版参数的个数打印出来,如果我们需要将参数包中的每个参数打印出来的话就需要通过一些方法了。展开可变模版参数函数的方法一般有两种:一种是通过递归函数来展开参数包,另外一种是通过逗号表达式来展开参数包。下面来看看如何用这两种方法来展开参数包。
3.1递归函数方式展开参数包
通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止函数,递归终止函数正是用来终止递归的,来看看下面的例子。
#include <iostream>using namespace std;// 最终递归函数void print(){ cout << "empty" << endl; }// 展开函数template <typename T, typename... Args>void print(T head, Args... args){ cout << head << ","; print(args...); }int main(){ print(1, 2, 3, 4); return 0; }
上例会输出每一个参数,直到为空时输出empty。展开参数包的函数有两个,一个是递归函数,另外一个是递归终止函数,参数包Args...在展开的过程中递归调用自己,每调用一次参数包中的参数就会少一个,直到所有的参数都展开为止,当没有参数时,则调用非模板函数print终止递归过程。
递归调用的过程是这样的:
print(1,2,3,4);print(2,3,4);print(3,4);print(4);print();
上面的递归终止函数还可以写成这样:
template <class T>void print(T t){ cout << t << endl;}
修改递归终止函数后,上例中的调用过程是这样的:
print(1,2,3,4);print(2,3,4);print(3,4);print(4);
当参数包展开到最后一个参数时递归为止。
比如再加一个:
//最终递归函数void print() { cout << "empty" << endl; }template <class T>void print(T t){ cout << t<< endl;}template <class T>void print(T t, T t1){ cout << t<<"****" << t1<< endl;}// 展开函数template <typename T, typename... Args>void print(T head, Args... args){ cout << head << ","; print(args...);}int main(){ print(1, 2, 3, 4); return 0;}上面的调用顺序是print(1,2,3,4);print(2,3,4);print(3,4);
- c++ 可变参数模板展开原理
- c++-可变参数模板函数
- C可变参数实现原理
- C可变参数实现原理
- 揭秘C可变参数原理
- C 可变长参数 VS C++11 可变长模板
- C 可变长参数 VS C++11 可变长模板
- C 可变长参数 VS C++11 可变长模板
- C语言可变参数的原理
- C/C++中可变参数的原理
- C 语言可变参数实现原理
- C/C++中可变参数的原理
- C/C++中可变参数的原理
- C/C++ 可变参数实现原理
- C言语中可变参数的原理
- C/C++中可变参数的原理
- C语言可变参数函数实现原理
- C语言可变长参数实现原理
- 解读Predix 工业云平台,其实是一个“操作系统”
- vi/vim基本使用方法
- RPG游戏中的视野刷新算法
- mysql事务回滚机制概述
- 通过Spark Rest 服务监控Spark任务执行情况
- c++ 可变参数模板展开原理
- 有趣的Java-J05
- 比较好的自媒体平台推荐,揭秘哪个自媒体平台收入最高
- 预处理程序学习与分析(一)
- Linux网络接口配置文件解析
- 刷题训练——PAT (Basic Level)-1039
- ListView 返回顶部第一条
- 无法解析的外部符号, 但是已经添加的lib库
- 183. Customers Who Never Order