# 一、可变参数模板
#CPP11
# 1. 概述
C++ 的可变参数模板(Variadic Templates)是一种强大的特性,使得模板能够接受可变数量的参数。这一特性引入于 C++11,允许程序员创建更加灵活和通用的代码。
可变参数模板使得函数模板和类模板能够接受任意数量的模板参数,无论是类型参数还是非类型参数。它们为泛型编程提供了更大的灵活性。
# 2. 基本语法
可以通过使用省略号 ... 来定义参数包。
- 函数模板: - 1 
 2
 3
 4- template<typename... Args> 
 void func(Args... args) {
 // 处理参数
 }
- 类模板:同理。 - 1 
 2
 3
 4
 5
 6
 7- template<typename... Args> 
 class MyClass {
 public:
 MyClass(Args... args) {
 // 构造函数处理
 }
 };
# 3. 参数展开
展开参数包(pack expansion)是将模板参数包展开成单个参数序列。
在函数模板或类模板中,可以使用参数包展开来处理传入的参数。展开的方式通常使用以下语法:
- 在函数参数中展开:直接使用 args...。(见下文 递归模板 的举例)
- 在函数体中展开:使用 (..., expression)的形式。(即,使用折叠表达式进行展开)
| 1 | template<typename... Args> | 
# 4. 示例
以下是一个简单的示例,演示如何使用模板参数包:
| 1 | 
 | 
# 5. 递归模板
可以通过递归模板实现对参数包的处理。例如,计算参数包中所有数值的和:
| 1 | template<typename T> | 
# 6. 使用非类型模板参数
除了类型参数,模板参数包也可以使用非类型参数:
| 1 | template<int... Values> | 
# 7. 结合其他特性
模板参数包可以与其他 C++ 特性结合使用,如 SFINAE(Substitution Failure Is Not An Error)和类型推导,使得编写更加复杂的泛型代码变得可能。
# 二、折叠表达式
#CPP17
# 1. 基本概念
折叠表达式(Fold Expression)是 C++17 引入的一种特性,用于简化对可变参数模板的操作,尤其是在处理参数包时。它允许你对参数包中的元素进行简单的折叠运算(例如加法、乘法、逻辑运算等),减少了编写递归模板的需要。
折叠表达式是通过指定一个二元操作符(如 + 、 * 、 && 等),对参数包中的所有元素进行运算的简洁方式。
# 2. 语法
折叠表达式有四种主要形式:
- 一元右折叠(Unary Right Fold): ( ... op pack )
- 一元左折叠(Unary Left Fold): ( pack op ... )
- 二元右折叠(Binary Right Fold): ( init op ... op pack )
- 二元左折叠(Binary Left Fold): ( pack op ... op init )
具体地,有:
- 一元右折叠: - 1 
 2
 3
 4
 5
 6
 7
 8- template<typename... Args> 
 auto sum(Args... args) {
 return (args + ...); // 等价于 (((args1 + args2) + args3) + ...)
 }
 int main() {
 std::cout << sum(1, 2, 3, 4); // 输出: 10
 }
- 一元左折叠: - 1 
 2
 3
 4
 5
 6
 7
 8- template<typename... Args> 
 auto sum(Args... args) {
 return (... + args); // 等价于 (... + (args1 + (args2 + (args3 + ...))))
 }
 int main() {
 std::cout << sum(1, 2, 3, 4); // 输出: 10
 }
- 二元右折叠: - 1 
 2
 3
 4
 5
 6
 7
 8- template<typename... Args> 
 auto sum(Args... args) {
 return (0 + ... + args); // 初始化值为0,等价于 (0 + ((args1 + args2) + args3) + ...)
 }
 int main() {
 std::cout << sum(1, 2, 3, 4); // 输出: 10
 }
- 二元左折叠: - 1 
 2
 3
 4
 5
 6
 7
 8- template<typename... Args> 
 auto sum(Args... args) {
 return (args + ... + 0); // 初始化值为0,等价于 (... + (args1 + (args2 + (args3 + ... + 0))))
 }
 int main() {
 std::cout << sum(1, 2, 3, 4); // 输出: 10
 }
# 三、示例代码与解析
结合模板参数包和折叠表达式,我们可以编写出非常简洁和强大的模板函数。
例如,一个同时支持不同数据类型的打印函数:
| 1 | 
 | 
这里我们逐行解释上面的模板函数 print,并详细说明模板参数包和折叠表达式的工作原理。
- 模板声明: - 1 - template<typename... Args> 
 这一行代码声明了一个模板,其中- Args是一个模板参数包。- typename... Args表示- Args可以接受任意数量的模板参数。
- 函数定义: - 1 - void print(Args... args) { 
这一行定义了一个名为 print 的函数。 Args... args 表示 args 是一个函数参数包,对应于模板参数包 Args 。每个 Args 中的类型对应于一个 args 中的参数。
- 折叠表达式:1 (std::cout << ... << args) << '\n'; 
 这一行是函数体,使用了折叠表达式来输出所有参数,并在末尾输出一个换行符。
