当前位置: 首页 > news >正文

【C++基础知识】折叠表达式详解--结合上一篇

折叠表达式(Fold Expressions)是 C++17 引入的一种模板元编程技术,用于简化可变参数模板(variadic templates)的参数包展开。它允许以简洁的方式对参数包(parameter pack)中的所有元素进行递归式操作,如求和、逻辑运算、函数调用等。


1. 基本语法

折叠表达式的基本形式如下:

折叠方式语法示例展开形式(假设参数包为 args... = a, b, c
一元右折叠(pack op ...)(a op (b op c))
一元左折叠(... op pack)((a op b) op c)
二元右折叠(pack op ... op init)(a op (b op (c op init)))
二元左折叠(init op ... op pack)(((init op a) op b) op c)

其中:

  • pack 是参数包(如 args...)。
  • op 是操作符(如 +, &&, , 等)。
  • init 是初始值(仅用于二元折叠)。

2. 常见用途

(1) 求和(+ 折叠)

template<typename... Args>
auto sum(Args... args) {return (args + ...); // 一元右折叠:a + b + c
}

展开形式

return (a + (b + c));

(2) 逻辑运算(&&|| 折叠)

template<typename... Args>
bool all_true(Args... args) {return (args && ...); // 检查所有参数是否为 true
}

展开形式

return (a && (b && c));

(3) 逗号操作符折叠(, 折叠)

template<typename... Args>
void print_all(Args... args) {(std::cout << ... << args); // 一元左折叠:(((cout << a) << b) << c)
}

展开形式

((std::cout << a) << b) << c;

3. 为什么使用逗号操作符(,)折叠?

在最初的代码中:

((total_sum += Codec<remove_cvref_t<Args>>::compute_encoded_size(conditional_arg_size_cache, args)), ...);

使用的是逗号操作符折叠,而不是 + 折叠,原因如下:

(1) 保证求值顺序

  • + 折叠的求值顺序是未指定的(unspecified),编译器可以自由优化计算顺序:

    (args + ...); // 可能是 (a + b) + c,也可能是 a + (b + c)
    

    如果 compute_encoded_size 有副作用(如修改 conditional_arg_size_cache),顺序不一致会导致错误。

  • , 折叠的求值顺序是严格从左到右(C++17 起):

    (f(args), ...); // 保证 f(a), f(b), f(c) 按顺序执行
    

    因此,使用 , 折叠可以确保 compute_encoded_size 按参数顺序依次执行。

(2) 避免 + 折叠的潜在问题

如果写成:

total_sum += (Codec<Args>::compute_encoded_size(args) + ...);
  • + 折叠可能先计算所有 compute_encoded_size 再累加,导致 conditional_arg_size_cache 更新顺序错误。
  • , 折叠确保每次计算后立即累加,保证缓存正确更新。

4. 其他折叠表达式示例

(1) 二元左折叠(带初始值)

template<typename... Args>
auto sum_with_init(int init, Args... args) {return (init + ... + args); // 二元左折叠:(((init + a) + b) + c)
}

(2) 调用多个函数

template<typename... Funcs>
void run_all(Funcs... funcs) {(funcs(), ...); // 依次调用 func1(), func2(), func3()
}

(3) 检查是否所有参数满足条件

template<typename... Args>
bool all_even(Args... args) {return ((args % 2 == 0) && ...); // 检查是否全是偶数
}

5. 总结

特性说明
用途简化可变参数模板的参数包展开
求值顺序+* 等数学运算顺序未指定,, 严格从左到右
适用操作符+, -, *, /, &&, `
初始值支持二元折叠((init op ... op pack)(pack op ... op init)
主要优势代码简洁,避免递归模板展开

在最初的代码中,使用 , 折叠是为了确保 compute_encoded_size 按顺序执行,从而正确更新 conditional_arg_size_cache。这是折叠表达式在依赖求值顺序的场景下的典型应用。

http://www.dtcms.com/a/154781.html

相关文章:

  • Qt ModbusSlave多线程实践总结
  • 基于STM32、HAL库的MCP3421A0T模数转换器ADC驱动程序设计
  • Axure全局变量的含义与基础应用
  • 百度搜索AI开放计划:助力开发者通过MCP Server连接用户和应用
  • Spring Cloud Gateway 如何将请求分发到各个服务
  • 【Harmony OS】组件
  • 从零开始学Python游戏编程39-碰撞处理1
  • ESP-ADF esp_dispatcher组件之dispatcher介绍
  • RK3288 5.10内核无法点亮LVDS显示
  • Chrmo手动同步数据
  • 【软件工程】TCP三次握手中的SYN与ACK:核心机制详解
  • Vue3 上传后的文件智能预览(实战体会)
  • 如何申请游戏支付平台通道接口?
  • (六)机器学习---聚类与K-means
  • Python CT图像预处理——基于ITK-SNAP
  • 【DRAM存储器五十一】LPDDR5介绍--DFE与Pre-Emphasis
  • ⭐Unity_Demolition Media Hap (播放Hap格式视频 超16K大分辨率视频 流畅播放以及帧同步解决方案)
  • Spring-Cache替换Keys为Scan—负优化?
  • HTMLCSS模板实现水滴动画效果
  • 再谈String
  • Python的库
  • 【25软考网工】第三章(4)生成树协议、广播风暴和MAC地址表震荡
  • MySQL表达式之公用表表达式(CTE)的使用示例
  • Windows与CasaOS跨平台文件同步:SyncThing本地部署与同步配置流程
  • springboot2.x升级到3.x 惨痛经验总结
  • 告别 “幻觉” 回答:RAG 中知识库与生成模型的 7 种对齐策略
  • 力扣-hot100(找到字符串中的所有字母异位词)
  • Chromium 134 编译指南 Ubuntu篇:依赖同步与Hooks配置(六)
  • python打印颜色(python颜色、python print颜色、python打印彩色文字、python print彩色、python彩色文字)
  • vue项目前后端分离设计