网站首页 > 基础教程 正文
1、概述
我们知道模板通过对类型的泛化,让类或者函数具有更广泛的适应性。c++11进一步拓展了模板的范型能力,类型参数的个数可以是不确定的,这被称为可变参数模板(Variadic templates)。
可变参数模板可以采用任意类型和任意数量的模板参数,下面是一个可变参数的类模板定义:
“...”表示Arguments的个数和类型都是不确定的,容易知道,象下面这样创建此类模板的实例都是合法的:
当然,模板参数个数是0也是合法的,比如:
用户也可以把确定参数和可变参数混合起来,象下面这样声明模板:
这时候,用户实例化时必须至少指定一个模板参数,上面的例子中,v4的声明就变成非法的了(因为类型T没有确定)。不过话又说回来,如果模板声明时T有默认类型,比如:
则v4的声明又是有效的了(T被确定为int类型)。
函数模板的创建与上述方式类似,比如:
特别的,为了支持引用传参,可以这样声明:
2、可变参数模板的展开
为了让可变参数模板工作,得有一定的方法对每个参数执行一定的操作,这个过程可以叫展开,一般常用的方法是递归方式展开,通过对模板的特化,使模板实例化过程形成一系列模板的实例化,从而巧妙的展开模板。
假设我们要定义一个函数模板,需要打印任意个输入参数,中间用空格隔开,最后输出一个换行,可以如下定义:
递归调用过程一目了然(std::forward其实没什么作用,因为我们输出时并没有(也没必要)移动变量),假如我们用templatePrint(1,2,"123",10.5+3)来调用这个模板,则编译器会按照最佳匹配的原则依次实例化出如下版本的函数:
这些函数依次执行会按预期打印出所有的参数,这个方案的缺点是所谓的代码膨胀,会增加编译时间和可执行文件的体积。
可变参数的类模板的展开可以采用递归继承的方式进行,参数个数多的类层层继承参数个数少一个的类,思想和上述方案类似,这里不再赘述;
3、另一种展开方式
c++11提供的初始化列表支持'...'运算符,所以我们可以通过初始化列表来展开一个函数模板,还以上面的例子为例,可以做如下实现:
这个方案简化了很多,没有递归过程,利用初始化列表和逗号表达式依次对每个参数调用输出的操作,逗号表达式是为了使每一项最终有个输出值0。代码中的v是没有实际用处的,void的那一行是为了消除某些编译器对未使用变量的告警。
4、应用的例子
使用可变参数模板常常可以达到一些神奇的效果,模板编程的乐趣也在于此,这里仅举个例子,来源于小编开发的一个HTTP应用框架(https://github.com/an-tao/drogon),我们知道,HTTP应用常常需要对特定的路径做特定的处理,所以我希望框架能提供尽量灵活方便的处理函数注册接口,使用可变参数模板技术,最后达成的效果是这样的:
可以看到,本例子中,我们把一个lambda表达式注册到形如“/api/v1/handle1/{1}/{2}/?p3={3}&p4={4}”的路径上,框架把路径上占位符号代表的参数转换成对应类型的变量,按箭头所示的映射方式传入这个HTTP请求处理函数。
为了给HTTP应用开发提供最大的灵活性,我们不应该对这个处理函数的参数类型和参数个数做任何限定,这个场景里,除了用可变参数模板(当然还要配合类型萃取等模板技术),用其他技术是很难达到这样的效果的。
具体的实现,列在这里就显得过于累赘了,感兴趣的朋友可以自行去github上浏览,欢迎加星,更欢迎提出宝贵意见,这里也算是小编夹带私货了,不过也算切题,吼吼。
- 上一篇: c++对于内建类型的默认初始化 创建内部类的对象
- 下一篇: C++系列1-1:初探C++ c=2μf
猜你喜欢
- 2024-10-10 C++系列1-1:初探C++ c=2μf
- 2024-10-10 数组的初始化方式有哪几种? 数组的初始化是什么意思
- 2024-10-10 c++对于内建类型的默认初始化 创建内部类的对象
- 2024-10-10 C++类构造函数,如何初始化对象?linux C++第27讲
- 2024-10-10 【C++编程语言】之 类和对象——对象的初始和消除
- 2024-10-10 C++基础语法梳理:引用、封装、继承和多态
- 2024-10-10 C++核心准则?:按照成员声明的顺序定义和初始化成员变量
- 2024-10-10 C++核心准则C.47:按照成员变量声明的次序定义和初始化数据成员
- 2024-10-10 C/C++语言编程系列002——不同情况下数组的初始化方法
- 2024-10-10 c++面试常见问题汇总—建议收藏 c++面试题总结
- 最近发表
- 标签列表
-
- gitpush (61)
- pythonif (68)
- location.href (57)
- tail-f (57)
- pythonifelse (59)
- deletesql (62)
- c++模板 (62)
- css3动画 (57)
- c#event (59)
- linuxgzip (68)
- 字符串连接 (73)
- nginx配置文件详解 (61)
- html标签 (69)
- c++初始化列表 (64)
- exec命令 (59)
- canvasfilltext (58)
- mysqlinnodbmyisam区别 (63)
- arraylistadd (66)
- node教程 (59)
- console.table (62)
- c++time_t (58)
- phpcookie (58)
- mysqldatesub函数 (63)
- window10java环境变量设置 (66)
- c++虚函数和纯虚函数的区别 (66)