C++ 折叠表达式(Fold Expression)是在 C++17 引入的一种语法,用于简化与可变参数模板的操作。折叠表达式的作用是对参数包(parameter pack)进行递归处理。
折叠表达式有四种类型:
- 一元左折叠 (Unary Left Fold):
(... op pack)
这会从左向右地将操作符 op
应用于参数包中的元素。
例子:
template<typename... Args>
auto sum(Args... args) {
return (... + args); // 左折叠:((arg1 + arg2) + arg3) + ...
}
- 一元右折叠 (Unary Right Fold):
(pack op ...)
这会从右向左地将操作符 op
应用于参数包中的元素。
例子:
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // 右折叠:arg1 + (arg2 + (arg3 + ...))
}
- 二元左折叠 (Binary Left Fold):
(init op ... op pack)
在左折叠的基础上增加一个初始值 init
。折叠从左至右,并将 init
作为第一个操作数。
例子:
template<typename... Args>
auto sum(Args... args) {
return (0 + ... + args); // 左折叠,初始值为 0
}
- 二元右折叠 (Binary Right Fold):
这与二元右折叠类似,只不过 init
是最后一个操作数,折叠从右至左。
例子:
template<typename... Args>
auto sum(Args... args) {
return (args + ... + 0); // 右折叠,初始值为 0
}
常见的应用场景
- 参数包的求和、乘积。
- 参数包中元素的逻辑与/或操作。
- 结合可变参数模板,简化递归调用的代码。
应用示例对比:
#include <iostream>
#方法1 输出函数不定方法
template< typename Last >
void log(Last param) {
std::cout << "Output last param:"<< param << std::endl;
}
template< typename First, typename... Paramlist >
void log(First v, Paramlist... args) {
std::cout << "Traversal param:"<< v << std::endl;
log(args...);
}
#方法2 输出函数不定方法
template<typename T, typename... Ts>
auto printf3(T value, Ts... args) {
std::cout <<"printf3:" << value << std::endl;
(void) std::initializer_list<T> {
//(... op pack)
//这是一个lambda 表达式,通过 [] 捕获 args,并对每个 args 执行输出操作:
//value... 展开参数包,将 args... 中的每一个元素都以 lambda 表达式的形式传递,并展开执行。每个 args 被捕获到 lambda 中,展开后生成多个语句。相当于:
//std::cout << args1 << std::endl;
//std::cout << args2 << std::endl; ...
([&args] { std::cout << "Paramlist list:"<<args << std::endl;}(), value) ...
...
};
}
//方法3 输出不定参数
template<typename ... T>
auto sum(T ... t) {
return (0 + ... + t);//(t + ...) 是左折,表达式会依次进行累加操作,像这样展开(((t1 + t2) + t3) + t4) + ... ,
// 这样即使参数包为空,也返回初始值 0
}
int main() {
log("Hi", "test", 123, 1.1);
printf3("first", "second", 3, 4.4);
std::cout << sum(1, 2, 3, 4, 5.1) << std::endl;
return 0;
}
~
通过折叠表达式,可以避免手动展开参数包的递归调用,简化代码编写,提升可读性。