C++如何强制operator+这类左结合运算符实现右结合逻辑
问题根因
你当前代码失败的核心原因是:处理三层及以上的加法时,新加入的右侧Tag类型被直接包裹在次外层X的右参数位置,没有递归插入到最内层的右节点,导致a+b+c+d生成的实际类型是X<A, X<X<B,C>, D>>,和预期的X<A, X<B, X<C,D>>>不匹配。
解决思路
新增递归构造逻辑,不管左侧的X嵌套了多少层,都把新加入的右侧Tag类型插入到X结构的最内层右节点位置,模拟右结合的运算符优先级。
完整实现代码
#include <cstdio> #include <utility> #include <type_traits> struct Tag{};//for class tagging struct A: public Tag{}; struct B: public Tag{}; struct C: public Tag{}; struct D: public Tag{}; struct X0{}; template<typename L, typename R> struct X: public X0{//binary op to force right-associativity using TL = L; using TR = std::conditional_t<std::is_base_of_v<Tag,L> && std::is_base_of_v<Tag,R>, R&, R>; L& l; TR r; X(L&l, R&r): l{l}, r{r}{} X(L&l, R&&r): l{l}, r{std::forward<TR>(r)}{} }; // 递归构造右结合的X实例 template<typename L, std::derived_from<Tag> R> auto build_right_x(L&& l, R& r) { if constexpr (std::derived_from<std::remove_cvref_t<L>, Tag>) { return X{l, r}; } else { return X{l.l, build_right_x(l.r, r)}; } } template<std::derived_from<Tag> L, std::derived_from<Tag> R> auto operator+(L& l, R& r){return X{l, r};} //for: a+b template<std::derived_from<X0> L, std::derived_from<Tag> R> auto operator+(L&& l, R&r){return build_right_x(std::forward<L>(l), r);} //for all chained addition //================================================================ int main(){ A a; B b; C c; D d; printf("-------- a+b\n"); auto x2 = a+b; printf("-------- a+b+c\n"); auto x3 = a+b+c; // <=> (a+b)+c static_assert(std::is_same_v<decltype(x3), X<A, X<B,C>>>); printf("-------- a+b+c+d\n"); auto x4 = a+b+c+d; // <=> ((a+b)+c)+d static_assert(std::is_same_v<decltype(x4), X<A, X<B, X<C,D>>>>); // 现在可以正常通过 return 0; }
补充说明
这个实现利用C17的if constexpr做递归分支选择,不管链式加法有多少层,都能自动把结构调整为右结合的嵌套X类型。如果需要兼容更低版本的C标准,可以把递归逻辑用模板特化实现,效果是一致的。
内容的提问来源于stack exchange,提问作者Solo
相关产品推荐
相关产品推荐

