[C++11 模板的改进] --- 可变参数模板
Posted Overboom
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[C++11 模板的改进] --- 可变参数模板相关的知识,希望对你有一定的参考价值。
C++11之前,类模板和函数模板只能含有固定数量的模板参数,C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。
可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,申明可变参数模板时需要在typename或class后面带上省略号 “…”
1 可变参数模板函数
1.1 可变参数模板函数的定义
一个可变参数模板函数的定义如下:
template <class... T>
void f(T... args)
cout<<sizeof...(args)<<endl; //打印变参的个数
f(); //0
f(1,2); //2
f(1,2.5,""); //3
1.2 参数包的展开
1.2.1 递归方式展开
通过递归方式展开函数包,需要提供一个参数包展开函数和一个终止递归函数。
#include <iostream>
using namespace std;
// 终止递归函数
void print()
cout << "empty" << endl;
// 展开函数
template <class T,class ...Args>
void print(T head,Args... rest)
cout << "parameter "<<head << endl; //打印变参的个数
print(rest...);
int main()
print(1, 2, 3, 4);
return 0;
/*
运行结果:
parameter 1
parameter 2
parameter 3
parameter 4
empty
*/
1.2.2 非递归方式展开
递归函数展开参数包是一种标准做法,也比较好理解,但也有一个缺点,就是必须有一个重载的递归终止函数,即必须有一个同名的终止函数来终止递归,这样会感觉稍有不便。其实还有一种方法可以不通过递归方式来展开参数包。比如:
#include <iostream>
using namespace std;
template <class T>
void printarg(T t)
cout << t << endl;
template <class ...Args>
void expand(Args... args)
int arr[] = (printarg(args),0)... ;
int main()
expand(1, 2, 3, 4);
return 0;
2 可变参数模板类
2.1 可变参数模板类的定义
可变参数模板类是一个带可变模板参数的模板类,第1章中介绍的std::tuple就是一个可变模板类,它的定义如下:
template<class... Types>
class tuple;
这个可变参数模板类可以携带任意类型任意个数的模板参数:
std::tuple<int> tp1=std::make_tuple(1);
std::tuple<int, double> tp2=std::std::make_tuple(1, 2.5);
std::tuple<int, double,string> tp2=std::std::make_tuple(1, 2.5,"test");
可变参数模板的模板参数个数可以为0,所以下面的定义也是合法的:
std::tuple<> tp;
2.2 参数包的展开
2.2.1 模板递归和特化方式展开参数包
可变参数模板类的展开一般需要定义2~3个类,包括类声明和特化的模板类。如下方式定义了一个基本的可变参数模板类:
template<typename... Args>structSum;
template<typename First, typename... Rest>
struct Sum<First, Rest...>
enum value = Sum<First>::value +Sum<Rest...>::value);
template<typename Last>struct Sum<Last>
enum value = sizeof (Last);
这个sum类的作用是在编译期计算出参数包中参数类型的size之和,通过sum<int, double, short>::value就可以获取这3个类型的size之和为14。这是一个简单的通过可变参数模板类计算的例子,可以看到一个基本的可变参数模板应用类由三部分组成:
1> 第一部分:
template<typename... Args> struct sum
它是前向声明,声明这个类是一个可变参数模板类
2> 第二部分是类的定义:
template<typename First, typename... Rest>
struct sum<First, Rest...>
enum value = Sum<First>::value +Sum<Rest...>::value);
它定义了一个部分展开的可变参数模板类,告诉编译器如何递归展开参数包。
3> 第三部分是特化的递归终止类:
template<typename Last>struct Sum<Last>
enum value = sizeof (Last);
上面的这种3段式的定义也可以改为两段式,去掉前向声明:
template<typename First, typename... Rest>
struct sum
enum value = Sum<First>::vlue+Sum< Rest...>::value);
;
template<typename Last>
enum value = sizeof(Last); ;
2.2.2 继承方式展开参数包
除了通过模板递归和模板特化的方式展开,还有另外一种方式:通过继承和特化的方式展开。下面的例子就是通过继承的方式去展开参数包
//整数序列的定义
template<int...>
struct IndexSeq;
//继承方式,开始展开参数包
template<int N, int... Indexes>
struct MakeIndexes : MakeIndexes<N-1, N-1, Indexes...> ;
//模板特化,终止展开参数包的条件
template<int... Indexes>
struct MakeIndexes<0, Indexes...>
typedef IndexSeq<Indexes...> type;
;
int main()
using T = MakeIndexes<3>::type;
cout<<typeid(T).name()<<endl;
return 0;
最终输出的类型是struct IndexSeq<0, 1, 2>
以上是关于[C++11 模板的改进] --- 可变参数模板的主要内容,如果未能解决你的问题,请参考以下文章