由来

  现在有这样一种需求:编写一个函数,可以接受任意数量的参数,并实现分别对每个参数进行操作的功能。所以,这就牵扯到了可变参函数模板,其最大的有点就是,可以任意输入参数的个数,要想创建可变参函数的板板,主要理解几个要点:

  • 模板参数包
  • 函数参数包
  • 展开参数包
  • 递归

模板和函数参数包

  要想了解模板和函数参数包,首先要看下见得的模板函数:

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显示的value1,这就完成了一个工作;
  接下来调用:test(argvs...),考虑到参数展开argvs...的作用,该语句与test(2, 3.0, "aa”)是等价的,正如前面说的,列表将每次减少一项,通过递归调用逐步缩小包,当argvs为空时,将调用不接受任何函数的test(),则程序结束;


琼筵醉月
12 声望11 粉丝