C++怎么使用折叠表达式_C++17语法教程【简洁】

11次阅读

折叠表达式需明确操作符及方向:左折叠为 (args + …),右折叠为 (… + args);减法等非常结合运算须选右折叠;空参数包时需初始值如 (0 + … + args)。

C++ 怎么使用折叠表达式_C++17 语法教程【简洁】

折叠表达式在可变参数模板里怎么写对

写错最常见:把 …… 放错位置,或者漏掉左 / 右折叠方向。折叠不是自动展开所有参数,它必须明确作用在某个操作符上,且操作符得支持对应元数(比如 + 是二元,sizeof…… 是一元)。

实操建议:

  • 左折叠写成 (args + ……),等价于 ((a1 + a2) + a3) + ……;右折叠是 (…… + args),等价于 a1 + (a2 + (a3 + ……))
  • 若操作符不满足结合律(比如 -/),左右折叠结果不同,必须按语义选——求和用哪个都行,但减法必须用右折叠 (…… - args) 才符合直觉
  • 空参数包时,左折叠 (args + ……) 编译失败(无操作数),右折叠 (…… + args) 同样失败;只有带初始值的版本如 (0 + …… + args) 才能安全处理空包

为什么 std::cout 会报错

因为 是左结合,但折叠要求操作符两侧类型兼容。直接写 <code>std::cout 会被解析为 <code>((std::cout,而 <code>std::cout 返回的是 <code>std::ostream&,后续再 就没问题——但编译器不这么推导,它需要显式左折叠语法。

正确写法只有一种:

立即学习 C++ 免费学习笔记(深入)”;

  • 用逗号运算符兜底:((std::cout,靠逗号保证每个 <code>std::cout 都执行,且不依赖返回值类型统一
  • 或封装一层函数对象,避免在折叠中混用流对象和值
  • 别用 std::cout —— 这是右折叠,语义错(先算最右边,但 <code>std::cout 不是右操作数)

折叠表达式和 std::apply 有什么区别

折叠是编译期展开,std::apply 是运行期解包 tuple。前者零开销、类型全在编译期确定;后者要传 tuple,有构造 / 解构成本,且无法做模板参数推导优化。

选哪个看场景:

  • 纯类型计算、SFINAE 判断、static_assert 检查,只能用折叠表达式——std::apply 是运行期,进不了编译期上下文
  • 需要把参数转成 tuple 再转发(比如存起来延迟调用),才用 std::apply
  • 性能敏感路径(比如 hot loop 里的日志打印宏),折叠更轻量;但若参数来自 runtime 容器,根本没法用折叠

VS2017 和 GCC7 对折叠的支持差异

VS2017 默认不启用 C++17 模式,即使开了 /std:c++17,早期版本仍对右折叠 (…… op args) 支持不全;GCC7 要求 -std=c++17,且不支持带初始化子句的折叠(如 (0 + …… + args))直到 GCC8。

跨编译器稳妥写法:

  • 优先用左折叠 (args + ……) 或带初值的左折叠 (0 + …… + args),兼容性最好
  • 避免单独使用右折叠,除非明确知道目标编译器版本
  • 在 CI 中至少覆盖 GCC8+、Clang7+、MSVC19.14+,老版本 MSVC 建议加 static_assert(__cplusplus >= 201703L, "C++17 required")

折叠表达式看着简单,但空参数包、操作符结合性、编译器实现差异这三点,实际写的时候八成会卡住。别指望一次写对,先跑通一个带初值的左折叠,再逐步放开限制。

text=ZqhQzanResources