C++ 折叠表达式

文章介绍了C++17引入的折叠表达式特性,用于简化参数包处理。折叠表达式包括一元左折叠、一元右折叠、二元左折叠和二元右折叠,可用于求和、求积、求最大值、求最小值、打印和函数调用等操作。文章提供了多个示例来展示如何使用这些折叠表达式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
}
### C++ 折叠表达式概述 折叠表达式C++17引入的一种强大工具,用于简化对模板参数包的操作。它允许开发者通过简单的语法结构对一组参数执行统一的操作[^1]。 #### 基本概念 折叠表达式的核心在于其能够将一系列参数按照指定的运算符连接起来形成一个完整的表达式。它可以分为两种形式:**左折叠**和**右折叠**[^2]。 - **左折叠 (Left Fold)** 形如 `(expr1 op expr2 op ...)`,表示从左到右依次应用操作符`op`。 - **右折叠 (Right Fold)** 形如 `(... op exprN)`,表示从右向左依次应用操作符`op`。 #### 支持的操作符 折叠表达式支持多种类型的二元操作符,包括但不限于算术运算符(如`+`, `-`),逻辑运算符(如`&&`, `||`),以及比较运算符(如`<`, `>`)等[^4]。 --- ### 示例代码展示 以下是几个典型的折叠表达式应用场景及其对应的代码示例: #### 示例 1: 使用折叠表达式求和 下面的例子展示了如何利用折叠表达式计算多个参数的总和: ```cpp template<typename... Args> auto sum(Args... args) { return (... + args); // 左折叠:((args1 + args2) + ...) } int main() { std::cout << sum(1, 2, 3, 4) << std::endl; // 输出 10 return 0; } ``` 此代码片段中,`(… + args)` 是一种左折叠的形式,最终会展开为 `(((1 + 2) + 3) + 4)`[^2]。 --- #### 示例 2: 右折叠减法 另一个例子演示了右折叠的应用场景——连续减去初始值的情况: ```cpp template<typename... U> auto sub_right(U... paras) { return (paras - ... - 220); // 右折叠:(para1 - (para2 - (...) - 220)) } int main() { std::cout << sub_right(10, 20, 30, 40) << std::endl; // 输出 -180 return 0; } ``` 在此处,`(paras - ... - 220)` 表达的是一个右折叠过程,具体展开顺序是从最右侧开始逐步向前推进[^3]。 --- #### 示例 3: 判断所有布尔值是否均为真 该实例说明了如何借助逻辑与 (`&&`) 来验证所有的输入条件都满足特定的要求: ```cpp template<typename... Args> bool all_true(Args... args) { return (... && args); // 展开为 (((arg1 && arg2) && ...) && argN) } int main() { bool result = all_true(true, true, false); std::cout << std::boolalpha << result << std::endl; // 输出 false return 0; } ``` 这里采用了一种基于逻辑与的一元左折叠方法来判断整个序列的状态[^5]。 --- ### 注意事项与限制 尽管折叠表达式非常方便,但也存在一些局限性和需要注意的地方: - 它们只适用于单个类型的操作;如果尝试混合不同类型的数据,则可能导致编译错误。 - 并非所有操作符都能被合法地应用于折叠上下文中,比如赋值(`=`)或者逗号`,`等特殊符号。 - 对于复杂的业务逻辑而言,单纯依赖折叠表达式可能难以胜任,此时需考虑结合其他高级技巧共同解决问题。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值