• C++11的可变参数模板


    可变参数模板函数

    一个可变参数模板函数的定义如下:

    template <class... T>

    void f(T... args)

    {

      cout<<sizeof...(args)<<endl;        //打印变参的个数

    }

    f();        //0 

    f(1,2);      //2

    f(1,2.5,"");    //3

    1.递归函数方式展开参数包

    通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止函数,递归终止函数正是用来终止递归,来看下面的例子。

     1 #include <iostream>
     2 using namespace std;
     3 
     4 void print()
     5 {
     6     cout << "empty" << endl;
     7 }
     8 
     9 template <class T,class ...Args>
    10 void print(T head,Args... rest)
    11 {
    12     cout << "parameter "<<head << endl;        //打印变参的个数
    13     print(rest...);
    14 }
    15 
    16 int main()
    17 {
    18     print(1, 2, 3, 4);
    19     return 0;
    20 }

    输出结果为:

     2.逗号表达式和初始化列表方式展开参数包

    递归函数展开参数包是一种标准做法,也比较好理解,但也有一个缺点,就是必须有一个重载的递归终止函数,即必须有一个同名的终止函数来终止递归,这样会感觉稍有不便。其实还有一种方法可以不通过递归方式来展开参数包。比如:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 template <class T>
     5 void printarg(T t)
     6 {
     7     cout << t << endl;
     8 }
     9 
    10 template <class ...Args>
    11 void expand(Args... args)
    12 {
    13     int arr[] = { (printarg(args),0)... };
    14 }
    15 
    16 int main()
    17 {
    18     expand(1, 2, 3, 4);
    19     return 0;
    20 }

    也可以打印1,2,3,4四个数字。

    可变参数模板类

    可变参数模板类是一个带可变模板参数的模板类,第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;

    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。这是一个简单的通过可变参数模板类计算的例子,可以看到一个基本的可变参数模板应用类由三部分组成,第一部分是:

    template<typename... Args> struct sum

    它是前向声明,声明这个类是一个可变参数模板类;第二部分是类的定义:

    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)};

    }

    上面的这种3段式的定义也可以改为两段式,去掉前向声明:

    template<typename First, typename... Rest>

    struct sum

    {

      enum { value = Sum<First>::vlue+Sum< Rest...>::value);

    };

    template<typename Last>

    {

      enum { value = sizeof(Last); };

    }

    2.继承方式展开参数包

    除了通过模板递归和模板特化的方式展开,还有另外一种方式:通过继承和特化的方式展开。下面的例子就是通过继承的方式去展开参数包

     1 //整数序列的定义
     2 template<int...>
     3 struct IndexSeq{};
     4 
     5 //继承方式,开始展开参数包
     6 template<int N, int... Indexes>
     7 struct MakeIndexes : MakeIndexes<N-1, N-1, Indexes...> {};
     8 
     9 //模板特化,终止展开参数包的条件
    10 template<int... Indexes>
    11 struct MakeIndexes<0, Indexes...>
    12 {
    13     typedef IndexSeq<Indexes...> type;          
    14 };
    15 
    16 int main()
    17 {
    18     using T = MakeIndexes<3>::type;
    19     cout<<typeid(T).name()<<endl;
    20     return 0;
    21 }

    最终输出的类型是struct IndexSeq<0, 1, 2>

  • 相关阅读:
    freeswitch与外部网关链接
    dojo中DateTextBox日期格式yyyy-MM-dd转化为数据库中yyyyMMdd
    dojo中取DateTextBox中的值两种方法
    视频编码与封装方式详解
    音频编码汇总
    FusionCharts 3D双柱状图
    FusionCharts 2D双柱状图
    利用merge优化
    FusionCharts 2D条状图
    全表扫描出现db file sequential read
  • 原文地址:https://www.cnblogs.com/djcsch2001/p/15411551.html
Copyright © 2020-2023  润新知