在c++11开始引入了枚举类型enum class,在此之前enum关键字所声明的枚举更像是一个普通的常量集合,会将当前作用域视为访问空间,而enum class解决了这一问题。但作为类型也失去了像数字一样的位运算,尤其在使用Flags时会尤为困难,这里将会编写宏定义,自动生成完成运算符的重载。

enum class可以有一个明确的类型,可以是int32_t、int64_t等等,在运算符时要将枚举强制转换回本身整数类型时才可以进行运算,这里将会使用标准库提供的std::underlying_type_t(cppreference),即std::underlying_type_t<Enum>

#pragma once

#define ENUM_CLASS_FLAGS(Enum) \
inline constexpr Enum& operator|=(Enum& x, Enum y) { \
    return x = static_cast<Enum>( \
        static_cast<std::underlying_type_t<Enum>>(x) | static_cast<std::underlying_type_t<Enum>>(y) \
); } \
inline constexpr Enum& operator&=(Enum& x, Enum y) { \
    return x = static_cast<Enum>( \
        static_cast<std::underlying_type_t<Enum>>(x) & static_cast<std::underlying_type_t<Enum>>(y) \
); } \
inline constexpr Enum& operator^=(Enum& x, Enum y) { \
    return x = static_cast<Enum>( \
        static_cast<std::underlying_type_t<Enum>>(x) ^ static_cast<std::underlying_type_t<Enum>>(y) \
); } \
inline constexpr Enum operator| (Enum x, Enum y) { \
    return static_cast<Enum>( \
        static_cast<std::underlying_type_t<Enum>>(x) | static_cast<std::underlying_type_t<Enum>>(y) \
); } \
inline constexpr Enum operator& (Enum x, Enum y) { \
    return static_cast<Enum>( \
        static_cast<std::underlying_type_t<Enum>>(x) & static_cast<std::underlying_type_t<Enum>>(y) \
); } \
inline constexpr Enum operator^ (Enum x, Enum y) { \
    return static_cast<Enum>( \
        static_cast<std::underlying_type_t<Enum>>(x) ^ static_cast<std::underlying_type_t<Enum>>(y) \
); } \
inline constexpr bool operator! (Enum x) { \
    return !static_cast<std::underlying_type_t<Enum>>(x); \
} \
inline constexpr Enum operator~ (Enum x) { \
    return static_cast<Enum>(~static_cast<std::underlying_type_t<Enum>>(x)); \
}

template<typename Enum>
inline constexpr bool EnumHasFlag(Enum a, Enum b)
{
    return static_cast<bool>( static_cast<std::underlying_type_t<Enum>>(a & b) );
}

同时对于if来说该枚举值是无法直接使用的,最后添加一个EnumHasFlag来帮助枚举位运算。

枚举属于编译期的常量,靠编译期的常量计算与内联可以忽略该定义所带来的开销。