现代C++变长参数模板

一、变长参数模板定义

自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;
}

猜你喜欢

转载自blog.csdn.net/xunye_dream/article/details/114761058