[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 模板的改进] --- 可变参数模板的主要内容,如果未能解决你的问题,请参考以下文章

C++11 ——— 可变参数模板

C++11 ——— 可变参数模板

MSVC2015 更新 3 可变参数模板解决方法

C++11 可变参数模板

C++11:可变参数模板函数参数的数量?

C++11新特性:9—— C++11在函数模板和类模板中使用可变参数