可变模版参数函数


可变模板参数

C++11的新特性–可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数、任意类型的参数。

可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号“…”。比如我们常常这样声明一个可变模版参数:template<typename…>或者template<class…>,一个典型的可变模版参数的定义是这样的:

template <class... T>
void f(T... args);

上面的可变模版参数的定义当中,省略号的作用有两个:

  1. 声明一个参数包T… args,这个参数包中可以包含0到任意个模板参数;
  2. 在模板定义的右边,可以将参数包展开成一个一个独立的参数。

上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。


展开参数包

我们可以使用sizeof关键字来查看参数包中元素的个数在这里插入图片描述

尽管如此,但是却不能使用[]进行访问,这是因为sizeof()是在编译阶段就确定的值, 但是参数是一个范型,这个在运行时才会确定,所以不能直接进行访问。

在这里插入图片描述

递归函数方式展开参数包

通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止函数,递归终止函数正是用来终止递归的。
在这里插入图片描述

之所以需要递归终止函数是因为当递归出入的参数包为空的时候,print无法自己调用自己。
在这里插入图片描述

另外,当较泛化和较特化的模板函数同时存在的时候,最终程序会执行较特化的那一个。
在这里插入图片描述

基于这种情况,std::max函数只可以返回两个数的较大者,如果多个数,就可以通过不定参数的模板来实现:

#include <iostream>
template <typename T>
T my_max(T value) {
  return value;
}

template <typename T, typename... Types>
T my_max(T value, Types... args) {
  return std::max(value, my_max(args...));
}

int main() 
{
  std::cout << my_max(1, 5, 8, 4, 6) << std::endl;

	return 0;
}

在这里插入图片描述

或者实现一个将多个数相加的函数:

#include <iostream>
template<typename T>
T sum(T t)
{
    return t;
}
template<typename T, typename ... Types>
T sum(T first, Types ... rest)
{
    return first + sum<T>(rest...);
}
int main()
{
    std::cout<<sum(1, 2, 3, 4)<<std::endl; //10    
}

逗号表达式展开参数包

递归函数展开参数包是一种标准做法,但也有一个缺点,就是必须要一个同名的重载终止函数来终止递归,这样可能会感觉稍有不便。还有一种方法可以不通过递归方式来展开参数包,这种方式需要借助逗号表达式和初始化列表。
在这里插入图片描述

expand函数中的逗号表达式:(printarg(args), 0),先执行printarg(args),再得到逗号表达式的结果0。同时还用到了C++11的另外一个特性——初始化列表,通过初始化列表来初始化一个变长数组,{(printarg(args), 0)...}将会展开成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0), etc... ),最终会创建一个元素值都为0的数组int arr[sizeof...(Args)]。由于是逗号表达式,在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数,也就是说在构造int数组的过程中就将参数包展开了,这个数组的目的纯粹是为了在数组构造的过程展开参数包。我们可以把上面的例子再进一步改进一下,将函数作为参数,就可以支持lambda表达式了,从而可以少写一个打印函数:

在这里插入图片描述


参考资料:
泛化之美–C++11可变模版参数的妙用
【C++】C++11可变参数模板(函数模板、类模板)

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天也要写bug、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值