模板可变参数的展开
在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模板进行参数传递。

浙公网安备 33010602011771号