形参包及展开
最近在写IOU的时候想模仿上交的写法用形参包写一个可以接受不限参数的max或者min,但是真写起来坑太多了
形参包是c++11引入的语法,当使用形参包作为函数的形参时,可以传入不限个数以及类型的(0-....)参数。实质上形参包展开后就是使用逗号隔开的多个形参。
template <class T, class... Tp>
T reduce_max(T firstarg, Tp... args)
{
return max(firstarg, reduce_max(args...));
}
这里的参数class ...Tp就是一个模板形参包类型的声明格式。注意当形参包作为参数时只能写在最后一个位置上。
作为类型时使用Tp... 参数名作为形参包类型的声明。
对应有几个操作。
template<class ...Tp>
size_t get_len(Tp ... args)
{
cout << sizeof...(Tp) << endl;
cout << sizeof...(args) << endl;
}
使用sizeof...
运算符返回形参包的一些性质,前者返回类型个数,后者返回参数个数
形参包展开是指将打包的形参包展开为 int a, int c, int b, float d的形式,即展开为用逗号隔开的形参的形式
以上面的函数的为例,当传入
reduce_max(1,5,3,6,7)
时,其递归过程如下,我们不妨用中括号扩出形参包内的参数(不符合语法)
reduce(1, [5,3,6,7])
reduce(5,[3,6,7])
reduce(3,[6,7])
reduce(6,[7])
reduce(7,?) --5
reduce(?, ?)
.....
显然在最后一次递归时传入一个长度为0的形参包,这是没有意义的,而且如果不给出递归出口会导致无限递归。
解决的一种方法是再给出一个仅接受一个参数的重载
template <class T>
T reduce_max(T firstarg)
{
return firstarg;
}
这样当递归到第五步时会调用这个重载,从而终止递归。
亦或这像这样写(从上交那里学来的)
template <class T, class... Tp>
T reduce_max(T firstarg, Tp... args)
{
if constexpr (sizeof...(args) <= 0)
return firstarg;
else
return max(firstarg, reduce_max(args...));
}
使用constexpr让if后的表达式在编译期确定范围,从而为其创造静态的递归出口。
如果不加constexpr的话连编译期都过不了