一、变长参数模板定义
自C++11后,C++开始支持变长参数模板,允许任意个数、任意类别的模板参数,不需要在定义时将参数的个数固定。其形式定义如下:
template<typename... Ts> class Variadic;
其模板实例化:
1. 0个参数的模板类 Variadic<> zero;
2. 多个参数的模板类 Variadic<int, double, std::string, std::list<int>> sample;
也可以定义至少需要一个参数的模板类,其定义如下:
template<typename T, typename... Args> class Variadic;
二、变长参数特性识别
1.获取变长参数的个数
工具:sizeof...
#include <iostream>
using namespace std;
template<typename... Args>
void func(Args... args)
{
cout << "the count of 'args': " << sizeof...(args) << endl;
}
int main(int agrc, char* argv[])
{
func();
func(1);
func(1, 2);
func(1, 2, 3);
return 0;
}
Program stdout:
the count of 'args': 0
the count of 'args': 1
the count of 'args': 2
the count of 'args': 3
2.解包
1、递归模板函数
不断递归地向函数传递模板参数,以达到递归遍历所有模板参数的目的。
#include <iostream>
template<typename T0>
void my_printf(T0 value)
{
std::cout << value << std::endl;
}
template<typename T, typename... Ts>
void my_printf(T value, Ts... args)
{
std::cout << value << std::endl;
my_printf(args...);
}
int main()
{
my_printf(1, 1000, "123", 1.123, "HahaahaH");
return 0;
}
Program stdout:
1
1000
123
1.123
HahaahaH
2、变参模板展开
递归的解包模板参数,写起来有些繁琐。C++17开始支持变参模板展开,上述例子的实现可以用下面的代码替换:
template<typename T, typename... Ts>
void my_printf(T value, Ts... args)
{
std::cout << value << std::endl;
if constexpr(sizeof...(args) > 1)
my_printf(args...);
}
3、初始化列表展开
利用逗号表达式及std::initializer_list的特性。
template<typename T, typename... Ts>
void my_printf(T value, Ts... args)
{
std::cout << value << std::endl;
(void)std::initializer_list<T>{([&args]{
std::cout << args << std::endl;
}(), value)...};
}
4、折叠表达式
C++17开始支持(其实是C++编译器增强了变参类型推到的能力),如下代码实现n个数据的和:
#include <iostream>
template<typename ... T>
auto sum(T ... t)
{
return (t + ...);
}
int main()
{
std::cout << sum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << std::endl;
return 0;
}
求平均值:
#include <iostream>
template<typename ... T>
auto average(T ... t)
{
return (t + ...)/sizeof...(t);
}
int main()
{
std::cout << average(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) << std::endl;
return 0;
}