模板可变参数的展开

在C++中模板参数列表展开,有多种处理方案,下面介绍几种常见的方法
1.递归式展开:
假设我们有一个需求,参数列表个数不确定,函数处理所有的参数参数。
例如:fun(12,"hello",25.3,...);
定义函数模板fun

1 template<typename... T>
2 void fun(T... x) {
3 // 函数逻辑处理
4 }

此时呢,我们定义了函数fun,参数可以正常输入,可是函数参数x是一个范围包,无法单一使用,那么我们就需要考虑展开参数包,继续编写一个fun的重载版本

 

 1 template<typename... T>
 2 void fun(T... x) {
 3 // 函数逻辑处理
 4 }
 5 template<typename T,typename... Y>
 6 void fun(T a, Y... b) {
 7 // 此时对a进行处理
 8 std::cout << a << std::endl;
 9 // 进行递归
10 fun(b...);
11 }


重载版本具有两个参数,也就是说fun函数当参数大于1个时,第二个重载版本就会有优先权,当参数b不断本函数展开后,最后参数b个数为0时,调用第一个fun函数,因为第二个已经不满足了,于是递归被终止,参数被全部展开。
2.列表展开
这是一种固定格式的参数列表展开写法。示例代码如下

1 template<typename T>
2 void g(T a) {
3 std::cout << a << std::endl;
4 }
5 template<typename... ARG>
6 void f(ARG...arg) {
7 int arr[] = { (g(arg), 0)... };
8 }

我们使用g函数来依次处理f的参数包,{ (g(arg), 0)... };这一段是固定的写法,g函数会把arg参数包全部展开进行处理,列表中0,表示了一种推导,这里可以是一种类型(如:int),也可以是类型的变量,最终这个属性将被dectype推导,有一种情况,就是 f(T x,Y... y),像这种情况就需要将参数x写在g函数的前面处理就可以。

1 template<typename T, typename... ARG>
2 void f(T x,ARG...arg) {
3 std::cout << x << std::endl;
4 int arr[] = { (g(arg), x)... };
5 }

 


这种参数列表展开,f并不会产生递归。
3.使用std::initializer_list展开

1 template<typename T, typename... ARG>
2 void Test(T x, ARG... arg) {
3 std::cout << x << std::endl;
4 (void)std::initializer_list<T>{
5 ([&arg] {std::cout << arg << std::endl; }(),x)...
6 };
7 }

这一种方法和第二种差不多,这里借用了初始化列表构造了一个lambda匿名函数处理参数包。
正常情况下,任意带有参数的函数都可以展开这种参数包,而展开的方法就是:
decltype(type) arr[] = { (function(arg),type())... };
arr的类型根据type类型推导,这种列表展开方法是固定的。

可以使用lambda模板进行参数传递。

 

posted @ 2021-09-16 14:29  大笨瓜  阅读(606)  评论(0)    收藏  举报