是,会触发无限递归。因折叠表达式展开的每个 args + ... 子调用都可能匹配泛型 operator+(t, t),导致模板反复实例化;应限定左操作数类型或用 common_type_t 静态断言参数可加性。

折叠表达式里用 operator+ 会触发无限递归?
直接在折叠表达式中写 (args + ...) 调用自定义 operator+,而该运算符又接受同类型参数包或自身类型时,编译器可能不断推导重载,最终报错 error: call to 'operator+' is ambiguous 或模板实例化深度超限。这不是语法错,是重载解析失控。
根本原因是:折叠表达式展开后生成的每个二元调用,都可能再次匹配你写的泛型 operator+,形成递归实例化链。
- 避免把变参模板的
operator+设计成接受任意两个同构类型(如T, T),尤其当T可能是你的包装类本身 - 显式限定左操作数类型,例如只允许
MyVec<t> operator+(const MyVec<t>&, const T&)</t></t>,不提供MyVec<t> operator+(const MyVec<t>&, const MyVec<t>&)</t></t></t> - 用
std::common_type_t或decltype在折叠前静态断言参数可加,比依赖重载解析更可靠
如何让 operator 支持变长参数且不和 <code>std::ostream 冲突
给自定义类型写 operator 时若用 <code>template<typename... args> MyType& operator,会和 <code>std::ostream& operator 形成重载歧义,尤其当传入字面量或标准类型时,编译器常选错。
正确做法是放弃通用转发,改用「左折叠 + 逐个注入」模式,并约束右操作数必须是你明确支持的类型:
template<typename t> MyType& operatortemplate<typename first typename... rest> MyType& operatorthis) (first); return (this) (rest)...; // 注意:这是 C++17 折叠,不是函数调用 }</typename></typename>
- 上面第二版其实是非法的——C++ 不允许对非成员函数做参数包折叠调用;真正可行的是把变参逻辑收进成员函数,如
template<typename... args> MyType& stream(Args&&... args) { (this->operator(args)), ...); return *this; }</typename...> - 更安全的是彻底避开重载
operator,改用命名方法如 <code>add()或push_all(),避免与标准库符号冲突 - 如果坚持用
operator,务必加 <code>enable_if限制右操作数类型,例如只接受int、double、std::string_view等白名单类型
sizeof...(Args) 为 0 时折叠表达式怎么不出错
像 (args * ...) 这种一元折叠,在参数包为空时默认展开为 1(乘法单位元),但 (args + ...) 展开为 0,而 (args && ...) 展开为 true。问题在于:这些默认值未必符合你的语义,比如向量加法空包不该返回标量 0,而应保持原对象不变或报错。
- 不要依赖折叠的隐式单位元,显式处理零参数情况:
if constexpr (sizeof...(Args) == 0) { return *this; } else { return (... + args); } - 用二元折叠规避单位元陷阱:
(init_value + ... + args),其中init_value是你可控的起点,如MyVec{} + ... + args - 注意:二元折叠要求至少一个参数,
sizeof...(Args) == 0时仍会编译失败,所以仍需if constexpr分支兜底
自定义运算符返回类型怎么统一适配折叠后的类型推导
折叠表达式类型由 decltype 推导,而多个 operator+ 调用链的中间类型可能不一致。例如 A + B 返回 Temp,Temp + C 又返回 Result,但折叠表达式要求所有步骤类型兼容,否则报 no match for 'operator+'。
- 强制所有运算符返回同一类型,比如始终返回
MyVec<auto></auto>(C++20)或用using result_type = std::common_type_t<decltype></decltype>统一 - 避免返回临时对象的引用(
const T&),折叠中每个子表达式都是右值,绑定到const T&会延长生命周期但不可靠;优先返回值类型 - 若涉及隐式转换(如
int→MyVec<int></int>),确保转换构造函数是explicit的,否则折叠中可能意外触发隐式转换,破坏类型一致性
最麻烦的从来不是写对折叠语法,而是让每一个被折叠调用的运算符,在类型、值类别、重载优先级上都不互相拆台。稍有松动,SFINAE 就变成硬错误,constexpr if 就卡在实例化阶段。动手前先画清楚调用图,比堆模板技巧管用。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











