0%

C++可变参数模板

C11可变参数模板

C++11可变参数模板

C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数、任意类型的参数 https://www.cnblogs.com/qicosmos/p/4325949.html

定义

可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号“...”。

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

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

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

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

可变模版参数和普通的模版参数语义是一致的,所以可以应用于函数和类,即可变模版参数函数和可变模版参数类

可变参数函数模版

1
2
3
4
5
6
7
8
9
template <class... T>
void f(T... args)
{
cout << sizeof...(args) << endl; //打印变参的个数
}

f(); //0
f(1, 2); //2
f(1, 2.5, ""); //3

递归函数方式展开参数包

通过递归函数展开参数包,需要提供一个参数包展开的函数和一个递归终止函数,递归终止函数正是用来终止递归的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
//递归终止函数
void print()
{
cout << "empty" << endl;
}
//展开函数
template <class T, class ...Args>
void print(T head, Args... rest)
{
cout << "parameter " << head << endl;
print(rest...);
}


int main(void)
{
print(1,2,3,4);
return 0;
}

上例会输出每一个参数,直到为空时输出empty。展开参数包的函数有两个,一个是递归函数,另外一个是递归终止函数,参数包Args...在展开的过程中递归调用自己,每调用一次参数包中的参数就会少一个,直到所有的参数都展开为止,当没有参数时,则调用非模板函数print终止递归过程。

递归调用的过程是这样的:

1
2
3
4
5
//print(1,2,3,4);
//print(2,3,4);
//print(3,4);
//print(4);
//print();

上面的递归终止函数还可以写成这样:

1
2
3
4
5
template <class T>
void print(T t)
{
cout << t << endl;
}
1
2
3
4
//print(1,2,3,4);
//print(2,3,4);
//print(3,4);
//print(4);

逗号表达式展开参数包

可变模版参数类