You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

枚举类型的复合赋值运算符是否应基于算术运算符定义?

枚举类型运算符重载:打破常规是否值得?

常规类的运算符重载惯例

通常,在重载算术/位运算符时,我们都会遵循「基于复合赋值运算符定义普通运算符」的惯例。核心逻辑是复合赋值直接操作对象本身,避免不必要拷贝,效率更高;普通运算符则通过值参传入对象,复用复合赋值逻辑,兼顾代码复用性。示例如下:

class SomeClass {
 SomeType data;
 // ...
 public:
 SomeClass& operator+=(const SomeClass& other) {
 data += other.data;
 return *this;
 }
 friend SomeClass operator+(SomeClass l, const SomeClass& r) {
 return l += r;
 }
 friend SomeClass& operator|=(SomeClass& l, SomeClass r) {
 l.data |= r.data;
 return l;
 }
 friend SomeClass operator|(SomeClass l, SomeClass r) {
 return l |= r;
 }
};

枚举类型的主流重载方案

但到了**枚举(包括未限定作用域枚举和enum class)**这里,社区主流方案却完全反过来:先定义普通算术/位运算符,再基于它们实现复合赋值运算符。比如:

using Underlying = uint8_t;
enum class SomeEnum : Underlying {
 A_VALUE = 0b0000'0001,
 B_VALUE = 0b0000'0010,
 // ...
 H_VALUE = 0b1000'0000,
 CLEAR_ALL = 0,
 SET_ALL = static_cast<uint8_t>(-1),
};

// 先定义普通位运算符
constexpr SomeEnum operator|(SomeEnum l, SomeEnum r) {
 return static_cast<SomeEnum>(static_cast<Underlying>(l) | static_cast<Underlying>(r));
}
// 基于普通运算符实现复合赋值
constexpr SomeEnum& operator|=(SomeEnum& l, SomeEnum r) {
 return l = l | r;
}

// 反例:常规顺序实现(仅作对比)
constexpr SomeEnum operator+=(SomeEnum& l, SomeEnum r) {
 Underlying ul = static_cast<Underlying>(l);
 ul += static_cast<Underlying>(r);
 return l = static_cast<SomeEnum>(ul);
}
constexpr SomeEnum operator+(SomeEnum l, SomeEnum r) {
 return l += r;
}

据社区反馈,这种反向写法更受青睐——相关讨论的两个方案发布时间仅差半小时,但前者获赞量远高于后者。

打破常规的争议点

这种反向做法的优势很直观:

  • 代码更简洁:普通运算符只需完成一次底层类型转换与运算,复合赋值直接复用逻辑,减少重复代码
  • 编译期友好:更容易实现constexpr支持,适配编译期计算场景

但它也带来了争议:

  • 违反最小惊讶原则:绝大多数场景下,开发者默认a += b比a + b更高效(前者直接操作对象,后者涉及临时对象拷贝),但枚举的这种实现中,operator+=依赖operator+,反而多了「运算+赋值」的步骤
  • 打破「优先用复合赋值提升效率」的默认认知

于是我们面临一个实际问题:在定义枚举类型的运算符(通常指位运算符,也涵盖其他类型)时,是否应该遵循主流建议,打破常规的重载顺序?

务实的选择

其实在枚举场景下,所谓的「效率差异」几乎可以忽略不计:枚举的底层类型都是整数,拷贝成本极低,operator+的临时对象开销微乎其微。而代码简洁性、编译期友好性的收益,在大多数枚举的使用场景(比如位掩码操作)中,远大于这点可忽略的效率损失。

当然,如果你的枚举被用在极端性能敏感的循环中,确实可以回到常规顺序,优先实现operator+=来避免那一点点额外操作。但对于绝大多数日常开发场景,遵循社区主流的反向写法是更务实的选择——毕竟代码的可读性、可维护性,以及符合社区共识的惯例,往往比那点几乎测不出来的效率更重要。

内容的提问来源于stack exchange,提问作者Justin Time - Reinstate Monica

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:08:41