C++17 折叠表达式
C++17折叠表达式[编辑 | 编辑源代码]
折叠表达式(Fold Expressions)是C++17引入的一项新特性,它允许对参数包(parameter pack)中的元素进行简洁的二元操作,从而简化可变参数模板(variadic templates)的编写。这一特性极大地提升了模板元编程的便利性,尤其在处理可变数量参数时。
基本概念[编辑 | 编辑源代码]
折叠表达式的基本思想是将一个二元操作符(如+
、*
、&&
等)应用于参数包中的所有元素,最终得到一个计算结果。折叠表达式可以用于以下四种形式:
1. 一元左折叠(Unary Left Fold):(... op pack)
2. 一元右折叠(Unary Right Fold):(pack op ...)
3. 二元左折叠(Binary Left Fold):(init op ... op pack)
4. 二元右折叠(Binary Right Fold):(pack op ... op init)
其中:
op
是二元操作符(如+
、*
、&&
等)。pack
是参数包(parameter pack)。init
是初始值(仅适用于二元折叠)。
一元左折叠示例[编辑 | 编辑源代码]
以下代码展示了一元左折叠的用法,计算参数包中所有元素的和:
#include <iostream>
template<typename... Args>
auto sum(Args... args) {
return (... + args); // 一元左折叠:(args1 + args2 + ... + argsN)
}
int main() {
std::cout << sum(1, 2, 3, 4, 5) << std::endl; // 输出:15
return 0;
}
输出:
15
解释:
(... + args)
展开为1 + 2 + 3 + 4 + 5
。- 最终结果为
15
。
一元右折叠示例[编辑 | 编辑源代码]
以下代码展示了一元右折叠的用法,计算参数包中所有元素的乘积:
#include <iostream>
template<typename... Args>
auto product(Args... args) {
return (args * ...); // 一元右折叠:(args1 * args2 * ... * argsN)
}
int main() {
std::cout << product(1, 2, 3, 4, 5) << std::endl; // 输出:120
return 0;
}
输出:
120
解释:
(args * ...)
展开为1 * 2 * 3 * 4 * 5
。- 最终结果为
120
。
二元折叠表达式[编辑 | 编辑源代码]
二元折叠表达式允许指定一个初始值(init
),并在此基础上对参数包进行折叠操作。
二元左折叠示例[编辑 | 编辑源代码]
以下代码展示了二元左折叠的用法,计算参数包中所有元素的和,并加上初始值:
#include <iostream>
template<typename... Args>
auto sum_with_init(int init, Args... args) {
return (init + ... + args); // 二元左折叠:(init + args1 + args2 + ... + argsN)
}
int main() {
std::cout << sum_with_init(10, 1, 2, 3, 4, 5) << std::endl; // 输出:25
return 0;
}
输出:
25
解释:
(init + ... + args)
展开为10 + 1 + 2 + 3 + 4 + 5
。- 最终结果为
25
。
二元右折叠示例[编辑 | 编辑源代码]
以下代码展示了二元右折叠的用法,计算参数包中所有元素的乘积,并乘以初始值:
#include <iostream>
template<typename... Args>
auto product_with_init(int init, Args... args) {
return (args * ... * init); // 二元右折叠:(args1 * args2 * ... * argsN * init)
}
int main() {
std::cout << product_with_init(10, 1, 2, 3, 4, 5) << std::endl; // 输出:1200
return 0;
}
输出:
1200
解释:
(args * ... * init)
展开为1 * 2 * 3 * 4 * 5 * 10
。- 最终结果为
1200
。
支持的操作符[编辑 | 编辑源代码]
折叠表达式支持几乎所有二元操作符,包括:
- 算术操作符:
+
、-
、*
、/
、%
- 逻辑操作符:
&&
、||
- 位操作符:
&
、|
、^
- 比较操作符:
<
、>
、==
、!=
- 逗号操作符:
,
逻辑操作符示例[编辑 | 编辑源代码]
以下代码展示了逻辑操作符的折叠用法,检查所有参数是否为真:
#include <iostream>
template<typename... Args>
bool all_true(Args... args) {
return (... && args); // 一元左折叠:(args1 && args2 && ... && argsN)
}
int main() {
std::cout << std::boolalpha << all_true(true, true, false, true) << std::endl; // 输出:false
std::cout << std::boolalpha << all_true(true, true, true) << std::endl; // 输出:true
return 0;
}
输出:
false true
解释:
- 第一个调用中,
(... && args)
展开为true && true && false && true
,结果为false
。 - 第二个调用中,展开为
true && true && true
,结果为true
。
实际应用场景[编辑 | 编辑源代码]
折叠表达式在模板元编程中非常有用,以下是几个实际应用场景:
打印所有参数[编辑 | 编辑源代码]
以下代码使用折叠表达式和逗号操作符打印所有参数:
#include <iostream>
template<typename... Args>
void print_all(Args... args) {
(std::cout << ... << args) << std::endl; // 二元左折叠:(cout << args1 << args2 << ... << argsN)
}
int main() {
print_all(1, " hello ", 3.14, " world"); // 输出:1 hello 3.14 world
return 0;
}
输出:
1 hello 3.14 world
解释:
(std::cout << ... << args)
展开为std::cout << 1 << " hello " << 3.14 << " world"
。- 最终输出为
1 hello 3.14 world
。
检查参数是否有序[编辑 | 编辑源代码]
以下代码使用折叠表达式检查参数是否按升序排列:
#include <iostream>
template<typename... Args>
bool is_sorted(Args... args) {
return (... < args); // 一元左折叠:(args1 < args2 < ... < argsN)
}
int main() {
std::cout << std::boolalpha << is_sorted(1, 2, 3, 4) << std::endl; // 输出:true
std::cout << std::boolalpha << is_sorted(1, 3, 2, 4) << std::endl; // 输出:false
return 0;
}
输出:
true false
解释:
- 第一个调用中,
(... < args)
展开为1 < 2 < 3 < 4
,结果为true
。 - 第二个调用中,展开为
1 < 3 < 2 < 4
,由于3 < 2
为false
,最终结果为false
。
总结[编辑 | 编辑源代码]
折叠表达式是C++17中一项强大的特性,它简化了可变参数模板的编写,使代码更加简洁和易读。通过一元或二元折叠,可以轻松实现参数包的聚合操作(如求和、求积、逻辑判断等)。在实际开发中,折叠表达式常用于模板元编程、泛型编程和函数式编程场景。