我发现eidolon目前接受的答案太危险了。编译器的优化器可能会对枚举中的可能值做出假设,并且您可能会得到带有无效值的垃圾。通常没有人想在标志枚举中定义所有可能的排列。
正如下面的 Brian R. Bondy 所说,如果您使用的是 C++11(每个人都应该这样做,那就太好了),您现在可以通过以下方式更轻松地做到这一点enum class
:
enum class ObjectType : uint32_t
{
ANIMAL = (1 << 0),
VEGETABLE = (1 << 1),
MINERAL = (1 << 2)
};
constexpr enum ObjectType operator |( const enum ObjectType selfValue, const enum ObjectType inValue )
{
return (enum ObjectType)(uint32_t(selfValue) | uint32_t(inValue));
}
// ... add more operators here.
这通过指定枚举的类型来确保稳定的大小和值范围,通过使用禁止将枚举自动向下转换为整数等enum class
,并用于constexpr
确保运算符的代码被内联,因此与常规数字一样快。
对于那些坚持使用 11 之前的 C++ 方言的人
如果我遇到了不支持 C++11 的编译器,我会在一个类中包装一个 int 类型,然后只允许使用位运算符和该枚举中的类型来设置其值:
template<class ENUM,class UNDERLYING=typename std::underlying_type<ENUM>::type>
class SafeEnum
{
public:
SafeEnum() : mFlags(0) {}
SafeEnum( ENUM singleFlag ) : mFlags(singleFlag) {}
SafeEnum( const SafeEnum& original ) : mFlags(original.mFlags) {}
SafeEnum& operator |=( ENUM addValue ) { mFlags |= addValue; return *this; }
SafeEnum operator |( ENUM addValue ) { SafeEnum result(*this); result |= addValue; return result; }
SafeEnum& operator &=( ENUM maskValue ) { mFlags &= maskValue; return *this; }
SafeEnum operator &( ENUM maskValue ) { SafeEnum result(*this); result &= maskValue; return result; }
SafeEnum operator ~() { SafeEnum result(*this); result.mFlags = ~result.mFlags; return result; }
explicit operator bool() { return mFlags != 0; }
protected:
UNDERLYING mFlags;
};
您可以像常规枚举 + typedef 一样定义它:
enum TFlags_
{
EFlagsNone = 0,
EFlagOne = (1 << 0),
EFlagTwo = (1 << 1),
EFlagThree = (1 << 2),
EFlagFour = (1 << 3)
};
typedef SafeEnum<enum TFlags_> TFlags;
用法也类似:
TFlags myFlags;
myFlags |= EFlagTwo;
myFlags |= EFlagThree;
if( myFlags & EFlagTwo )
std::cout << "flag 2 is set" << std::endl;
if( (myFlags & EFlagFour) == EFlagsNone )
std::cout << "flag 4 is not set" << std::endl;
您还可以enum foo : type
使用第二个模板参数,即typedef SafeEnum<enum TFlags_,uint8_t> TFlags;
.
我operator bool
用 C++11 的关键字标记了覆盖,explicit
以防止它导致 int 转换,因为这可能导致标志集在写出它们时最终折叠为 0 或 1。如果您不能使用 C++11,请忽略该重载并将示例用法中的第一个条件重写为(myFlags & EFlagTwo) == EFlagTwo
.