目录
1.可变参数模版
1.1概念
1.2递归方式展开参数包
1.3逗号表达式展开参数包
1.可变参数模版
1.1概念
C++11的新特性可变参数模板,这是一种允许模板函数或模板类接受任意数量参数的特性。可变参数模板极大地增强了模板的灵活性和表达能力,使得编写泛型代码更加方便。
可变参数模板通过使用省略号(...
)来表示参数包(parameter pack),参数包可以包含零个或多个参数。
// Args是一个模板参数包,args是一个函数形参参数包
// 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
template <class... Args>
void ShowList(Args... args)
{}
上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数 包”,参数包代表多个类型和多个参数,它里面包含了0到N(N>=0)个模版参数。
1.2递归方式展开参数包
我们如何将可变参数的函数传进来的参数进行处理呢?比如说对每个参数进行打印
// 这个函数不接受任何参数,它作为递归调用的终止条件。
void Print()
{
cout << endl;
}
// ...可接纳的模板参数个数仍然是0个及以上的任意数量,
// 但由于多了一个T类型,由此该模板可以接纳1个及其以上的模板参数。
template <class T, class... Args>
void Print(T t, Args... args)
{
cout << t << " ";
Print(args...); // 递归地调用自身,传入剩余的参数(args...)
}
// 打印参数包内容
template <class... Args>
void ShowList(Args... args)
{
Print(args...);
}
int main()
{
ShowList(1, "aaa", 2.2);
return 0;
}
执行流程
当ShowList(1, "aaa", 2.2);
被调用时,执行流程如下:
-
ShowList
函数将参数1
、"aaa"
和2.2
传递给Print
函数。 -
Print(1, "aaa", 2.2)
被调用:-
输出
1
,后面跟着一个空格。 -
递归调用
Print("aaa", 2.2)
。
-
-
Print("aaa", 2.2)
被调用:-
输出
"aaa"
,后面跟着一个空格。 -
递归调用
Print(2.2)
。
-
-
Print(2.2)
被调用:-
输出
2.2
,后面跟着一个空格。 -
递归调用
Print()
(基础函数)。
-
1.3逗号表达式展开参数包
template <class T>
void Print(T t)
{
cout << t << " ";
}
// 打印参数包内容
template <class... Args>
void ShowList(Args... args)
{
int arr[] = { (Print(args),0)... };
}
int main()
{
ShowList(1, "aaa", 2.2);
return 0;
}
int arr[] = { (Print(args),0)... };
这行代码使用了逗号运算符和初始化列表来展开参数包并调用Print
函数。具体解释如下:
-
逗号运算符:在C++中,逗号运算符(
,
)会计算其操作数的值,但只返回最后一个操作数的值(比如:int a = (1,2*2,3); 最终结果是a=3)。在这里,它用于确保Print(args)
被调用,但Print函数返回值(void
)被忽略,只保留0
作为逗号运算符的结果。 -
初始化列表:
int arr[] = {...}
是一个初始化列表,用于创建一个数组。数组中的每个元素都是通过逗号运算符表达式(Print(args),0)
初始化的。 -
参数包展开:
...
是参数包展开运算符,它将参数包中的每个参数args
展开为一个独立的逗号运算符表达式。
执行流程
当ShowList(1, "aaa", 2.2);
被调用时,执行流程如下:
-
ShowList
函数将参数1
、"aaa"
和2.2"
传递给初始化列表。 -
初始化列表展开参数包,生成逗号运算符表达式
展开成:int arr[] = {
最后:int arr[] = {0, 0, 0}(Print(1),0), (Print("aaa"),0), (Print(2.2),0)}
, -
这些
0
值被用来初始化一个临时数组arr
,但数组arr
在函数执行完毕后被销毁