由来
现在有这样一种需求:编写一个函数,可以接受任意数量的参数,并实现分别对每个参数进行操作的功能。所以,这就牵扯到了可变参函数模板,其最大的有点就是,可以任意输入参数的个数,要想创建可变参函数的板板,主要理解几个要点:
- 模板参数包
- 函数参数包
- 展开参数包
- 递归
模板和函数参数包
要想了解模板和函数参数包,首先要看下见得的模板函数:
template <typename T>
void test(T value)
{
cout << value << endl;
}
在上述简单的示例中,有两个参数列表,模板参数列表有且仅有T
,函数参数列表有且仅有value
。在C++ 11
中提供了一个省略号表示的元运算表,其目的就是能声明表示模板参数包的标识符;模板参数表实质上就是一个类型列表
,而函数参数表则一组与模板参数表中对应的值
,简单理解,模板参数包中数据 = 函数参数包中数据
。例如,将上述的模板函数改成可变参的模板函数:
template <typename... T>
void test(T... value)
{
......
}
解析下函数test(1, 2, 3., "aa","bb")
,模板参数包中包含的类型有:int, int, float, string, string,而函数参数包中包含值为: 1, 2, 3., "aa", "bb"。
展开参数包与递归
参数数量可变,但终究也只是一系列的参数,还是需要对参数包进行展开,依次处理。递归充其量只是一种思想,其目的就是为了展开函数参数包,对列表中的第一项进行处理,再将余下的内容递归调用,直到列表为空
,对于递归,确保递归的终止条件是很重要的,为了更清晰的说明此问题,下面提供一个简单的程序,通过解析语句理解:
#include <iostream>
void test() {} //当没有参数时,执行此函数
template <typename T>
void test(T value)
{
cout << "value = " << value << endl;
}
template <typename T, typename... Argv>
void test(T value, Argv... argvs)
{
cout << "value = " << value << ", " ;
test(argvs...);
}
int main()
{
test(1, 2, 3.0, "aa");
return 0;
}
程序说明:
test(1, 2, 3.0, "aa")
模板参数表为:int, int, float, string,函数参数表为:1, 2, 3.0, "aa",调用函数,cout
显示的value
为1
,这就完成了一个工作;
接下来调用:test(argvs...)
,考虑到参数展开argvs...
的作用,该语句与test(2, 3.0, "aa”)
是等价的,正如前面说的,列表将每次减少一项,通过递归调用逐步缩小包,当argvs
为空时,将调用不接受任何函数的test()
,则程序结束;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。