在C++17中引入了折叠表达式(Fold Expressions),它是C++模板元编程和可变参数模板(Variadic Templates)的一个重要扩展功能。折叠表达式允许对可变参数模板中的参数列表进行更简洁的操作,从而简化代码并提高可读性。
1. 折叠表达式的背景
在C++11和C++14中,可变参数模板允许函数或类模板接受任意数量的参数。然而,对这些参数进行操作时,通常需要使用递归模板展开的方式,代码较为复杂。例如,计算多个参数之和可能需要递归调用模板函数。C++17的折叠表达式则提供了一种更直接的方式。
2. 折叠表达式的语法
折叠表达式的基本形式如下:
- 左折叠(Left Fold):
(参数列表 op ...)
,从左到右依次对参数列表中的元素进行操作。 - 右折叠(Right Fold):
(... op 参数列表)
,从右到左依次对参数列表中的元素进行操作。 - 无操作符的折叠:
(参数列表 ...)
,通常用于将参数列表传递给其他函数。
其中,op
是一个二元操作符,如+
、*
、&&
、||
等。
3. 折叠表达式的应用场景
3.1 算术运算
假设有一个函数模板,需要计算多个参数的和:
template <typename... Args>
auto sum(Args... args) {
return (args + ...); // 左折叠
}
调用sum(1, 2, 3, 4)
时,展开为1 + 2 + 3 + 4
,结果为10
。
右折叠写法:
template <typename... Args>
auto sum(Args... args) {
return (... + args); // 右折叠
}
调用sum(1, 2, 3, 4)
时,展开为(((((0 + 1) + 2) + 3) + 4)
,结果也是10
。
3.2 逻辑运算
可以使用折叠表达式来判断多个条件是否都为真或至少有一个为真:
template <typename... Args>
bool all_true(Args... args) {
return (args && ...); // 左折叠
}
template <typename... Args>
bool any_true(Args... args) {
return (args || ...); // 左折叠
}
调用all_true(true, false, true)
返回false
,调用any_true(true, false, true)
返回true
。
3.3 打印参数列表
折叠表达式可以与std::ostream
等输出流结合,用于打印多个参数:
#include <iostream>
template <typename... Args>
void print(Args... args) {
(std::cout << ... << args) << std::endl; // 无操作符的折叠
}
int main() {
print("Hello", " ", "World", "!");
return 0;
}
输出:
Hello World!
3.4 调用函数
可以将参数列表传递给其他函数:
template <typename... Args>
void call_function(Args... args) {
f(args...); // 无操作符的折叠
}
假设有一个函数void f(int, double, char)
,调用call_function(1, 2.0, 'a')
会将参数传递给f
。
4. 折叠表达式的注意事项
- 折叠表达式只能用于可变参数模板的参数包(Parameter Pack)。
- 操作符必须是二元操作符,且参数类型必须支持该操作符。
- 无操作符的折叠主要用于将参数包传递给其他函数或模板。