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

如何优化enum class的operator|=等位运算操作符实现?

问题描述

我使用多年前他人分享的enum class进行位运算,并新增了operator|=和operator&=操作符,其底层类型为uint8_t、uint16_t或uint32_t。目前我仅能通过两种方式实现该功能:

版本1(使用临时变量):

#define ENUM_FLAG_OPERATOR1(T,X) inline T & operator X (T & lhs, T rhs) { std::underlying_type_t <T> V; V = static_cast<std::underlying_type_t <T>>(lhs); V X static_cast<std::underlying_type_t <T>>(rhs); lhs = (T) V; return  lhs; }

版本2(使用指针):

#define ENUM_FLAG_OPERATOR1(T,X) inline T & operator X (T & lhs, T rhs) {  (*(reinterpret_cast<std::underlying_type_t <T> *>(& lhs))) X static_cast<std::underlying_type_t <T>>(rhs);  return  lhs; }

配套的宏定义如下:

#define ENUM_FLAG_OPERATOR2(T,X) inline T operator X (T lhs, T rhs) { return (T) (static_cast<std::underlying_type_t <T>>(lhs) X static_cast<std::underlying_type_t <T>>(rhs)); }
#define ENUM_FLAGS(T, B) \
enum class T : B; \
inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); } \
ENUM_FLAG_OPERATOR2(T,|) \
ENUM_FLAG_OPERATOR2(T,^) \
ENUM_FLAG_OPERATOR2(T,&) \
ENUM_FLAG_OPERATOR1(T,|=) \
ENUM_FLAG_OPERATOR1(T,&=) \
enum class T : B 

使用示例:

ENUM_FLAGS(AutostartFlags, uint8_t)
{
    NO_FLAGS = 0,
    A = 0x01,
    B = 0x02,
    C = 0x10
};
AutostartFlags autostartDone_ = AutostartFlags::NO_FLAGS;
... 
autostartDone_ |= AutostartFlags::B;

请问是否存在更简洁、优雅的实现方式,无需临时变量或reinterpret_cast?我当前使用C14,运行环境为gcc 7.3.0,但也关注基于更高版本C的解决方案。


解决方案

C++14 兼容方案

可以通过一个模板辅助函数安全地获取enum class的底层类型引用,避免reinterpret_cast和临时变量的冗余:

辅助函数定义

#include <type_traits>

template <typename Enum>
constexpr auto& underlying_ref(Enum& e) noexcept {
    // 先转为void*再转底层类型指针,符合C++标准的类型转换规则
    return *static_cast<std::underlying_type_t<Enum>*>(static_cast<void*>(&e));
}

运算符实现

替换原有宏定义,直接实现运算符模板(或针对特定枚举类型实现):

// 一元取反
template <typename Enum>
inline Enum operator~(Enum t) noexcept {
    return static_cast<Enum>(~static_cast<std::underlying_type_t<Enum>>(t));
}

// 二元位运算
template <typename Enum>
inline Enum operator|(Enum lhs, Enum rhs) noexcept {
    return static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) | static_cast<std::underlying_type_t<Enum>>(rhs));
}

template <typename Enum>
inline Enum operator^(Enum lhs, Enum rhs) noexcept {
    return static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) ^ static_cast<std::underlying_type_t<Enum>>(rhs));
}

template <typename Enum>
inline Enum operator&(Enum lhs, Enum rhs) noexcept {
    return static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(lhs) & static_cast<std::underlying_type_t<Enum>>(rhs));
}

// 复合赋值运算
template <typename Enum>
inline Enum& operator|=(Enum& lhs, Enum rhs) noexcept {
    underlying_ref(lhs) |= static_cast<std::underlying_type_t<Enum>>(rhs);
    return lhs;
}

template <typename Enum>
inline Enum& operator&=(Enum& lhs, Enum rhs) noexcept {
    underlying_ref(lhs) &= static_cast<std::underlying_type_t<Enum>>(rhs);
    return lhs;
}

使用方式

无需再用ENUM_FLAGS宏,直接定义enum class即可:

enum class AutostartFlags : uint8_t
{
    NO_FLAGS = 0,
    A = 0x01,
    B = 0x02,
    C = 0x10
};

// 正常使用位运算
AutostartFlags autostartDone_ = AutostartFlags::NO_FLAGS;
autostartDone_ |= AutostartFlags::B;

如果需要限制仅针对特定枚举类型启用这些运算符,可以去掉模板,改为针对具体枚举类型实现,或者添加静态断言约束std::is_enum<Enum>::value和std::is_same<std::underlying_type_t<Enum>, uint8_t>::value等。


C++20+ 优雅方案

C++20引入了std::to_underlying和std::enum_class概念,能大幅简化实现,完全摆脱宏和不安全的转换:

#include <type_traits>

// 约束仅针对enum class类型
template <std::enum_class Enum>
constexpr Enum operator~(Enum e) noexcept {
    return static_cast<Enum>(~std::to_underlying(e));
}

template <std::enum_class Enum>
constexpr Enum operator|(Enum lhs, Enum rhs) noexcept {
    return static_cast<Enum>(std::to_underlying(lhs) | std::to_underlying(rhs));
}

template <std::enum_class Enum>
constexpr Enum operator^(Enum lhs, Enum rhs) noexcept {
    return static_cast<Enum>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
}

template <std::enum_class Enum>
constexpr Enum operator&(Enum lhs, Enum rhs) noexcept {
    return static_cast<Enum>(std::to_underlying(lhs) & std::to_underlying(rhs));
}

template <std::enum_class Enum>
constexpr Enum& operator|=(Enum& lhs, Enum rhs) noexcept {
    lhs = lhs | rhs;
    return lhs;
}

template <std::enum_class Enum>
constexpr Enum& operator&=(Enum& lhs, Enum rhs) noexcept {
    lhs = lhs & rhs;
    return lhs;
}

优势

  • 利用std::to_underlying直接获取枚举的底层值,无需手动static_cast
  • 通过std::enum_class概念确保运算符仅作用于强类型枚举
  • 所有运算符都是constexpr,支持编译期计算
  • 完全无需宏定义,代码更简洁易读

内容的提问来源于stack exchange,提问作者Ernie Mur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 12:05:20