C++ 折叠表达式是 C++17 新引入的一种语法特性,它可以简化对参数包的处理,避免使用递归模板。折叠表达式有四种形式,分别是一元右折叠、一元左折叠、二元右折叠和二元左折叠。它们的展开方式如下:
- 一元右折叠:(E op …) 展开为 (E1 op (… op (EN-1 op EN)))
- 一元左折叠:(… op E) 展开为 (((E1 op E2) op …) op EN)
- 二元右折叠:(E op … op I) 展开为 (E1 op (… op (EN−1 op (EN op I))))
- 二元左折叠:(I op … op E) 展开为 (((I op E1) op E2) op …) op EN)
其中,op 是支持的 32 个运算符之一,E 是参数包,I 是初始值。如果不指定初始值,则为一元折叠表达式;如果指定初始值,则为二元折叠表达式。当参数包为空时,只有 &&、|| 和 , 运算符有默认值,分别为 true、false 和 void()。
折叠表达式可以用于实现一些常见的操作,例如求和、求积、求最大值、求最小值、打印、调用等。下面是一些例子:
// 求和
template<typename... Args>
auto sum(Args... args) {
return (... + args); // 一元左折叠
}
// 求积
template<typename... Args>
auto product(Args... args) {
return (args * ...); // 一元右折叠
}
// 求最大值
template<typename... Args>
auto max(Args... args) {
return (args > ... ? args : ...); // 二元右折叠
}
// 求最小值
template<typename... Args>
auto min(Args... args) {
return (... < args ? ... : args); // 二元左折叠
}
// 打印
template<typename... Args>
void print(Args... args) {
((std::cout << args << " "), ...); // 一元左折叠
}
// 调用
template<typename F, typename... Args>
void apply(F f, Args... args) {
(f(args), ...); // 一元左折叠
}
#include <iostream>
#include <vector>
// 折叠表达式
template<typename... Args>
int Print( Args... args){
return (... + args);
}
template<typename T>
class AddSplit;
template<typename... Args>
void Cout(Args const&... args){
//(std::cout<<...<<args)<<std::endl; // 默认参数间没有空格
(std::cout<<...<<AddSplit<Args>(args) )<<std::endl;
}
// 用于处理参数间隔字符模板类
template<typename T>
class AddSplit{
friend std::ostream& operator<<(std::ostream& cout, AddSplit<T> sp){
return cout<<sp.arg<<sp.split;
}
public:
AddSplit(T const& arg, char c=' '): arg(arg), split(c){}
private:
T const& arg;
char split;
};
// template<typename T>
// std::ostream& operator<<(std::ostream& cout, AddSplit<T> sp){
// return cout<<sp.arg<<sp.split;
// }
template<typename ...Args>
int anverge(Args... args) {
const int size = sizeof...(args);
std::cout<<"size:"<<size<<std::endl;
return (args+...)/size;
}
void Test()
{
std::cout<<Print(1,2,3,4)<<std::endl;
Cout("hello",1, true);
}
int main()
{
Test();
return 0;
}