栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

[C++11 模板的改进] --- 可变参数模板

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

[C++11 模板的改进] --- 可变参数模板

C++11之前,类模板和函数模板只能含有固定数量的模板参数,C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板。
可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,申明可变参数模板时需要在typename或class后面带上省略号 “…”

1 可变参数模板函数 1.1 可变参数模板函数的定义

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

template 
void f(T... args)
{
  cout< 
1.2 参数包的展开 
1.2.1 递归方式展开 

通过递归方式展开函数包,需要提供一个参数包展开函数和一个终止递归函数。

#include 
using namespace std;

// 终止递归函数
void print()
{
    cout << "empty" << endl;
}

// 展开函数
template 
void print(T head,Args... rest)
{
    cout << "parameter "<
    print(1, 2, 3, 4);
    return 0;
}


1.2.2 非递归方式展开

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

#include 
using namespace std;

template 
void printarg(T t)
{
    cout << t << endl;
}

template 
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 tuple;

这个可变参数模板类可以携带任意类型任意个数的模板参数:

std::tuple tp1=std::make_tuple(1);
std::tuple tp2=std::std::make_tuple(1, 2.5);
std::tuple tp2=std::std::make_tuple(1, 2.5,"test");

可变参数模板的模板参数个数可以为0,所以下面的定义也是合法的:

std::tuple<> tp;
2.2 参数包的展开 2.2.1 模板递归和特化方式展开参数包

可变参数模板类的展开一般需要定义2~3个类,包括类声明和特化的模板类。如下方式定义了一个基本的可变参数模板类:

templatestructSum;

template
struct Sum
{
  enum { value = Sum::value +Sum::value);
}

templatestruct Sum
{
  enum { value = sizeof (Last)};
}

这个sum类的作用是在编译期计算出参数包中参数类型的size之和,通过sum::value就可以获取这3个类型的size之和为14。这是一个简单的通过可变参数模板类计算的例子,可以看到一个基本的可变参数模板应用类由三部分组成:
1> 第一部分:

template struct sum

它是前向声明,声明这个类是一个可变参数模板类

2> 第二部分是类的定义:

template
struct sum
{
  enum { value = Sum::value +Sum::value);
}

它定义了一个部分展开的可变参数模板类,告诉编译器如何递归展开参数包。

3> 第三部分是特化的递归终止类:

templatestruct Sum
{
  enum { value = sizeof (Last)};
}

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

template
struct sum
{
  enum { value = Sum::vlue+Sum< Rest...>::value);
};

template
{
  enum { value = sizeof(Last); };
}
2.2.2 继承方式展开参数包

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

//整数序列的定义
template
struct IndexSeq{};

//继承方式,开始展开参数包
template
struct MakeIndexes : MakeIndexes {};

//模板特化,终止展开参数包的条件
template
struct MakeIndexes<0, Indexes...>
{
    typedef IndexSeq type;
};

int main()
{
    using T = MakeIndexes<3>::type;
    cout< 

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/951789.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号