我找到了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
,并通过使用禁止将枚举自动向下转换为int等,并用于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
使用第二个模板参数(即)覆盖二进制稳定枚举的基础类型(如C ++ 11的)typedef SafeEnum<enum TFlags_,uint8_t> TFlags;
。
我operator bool
用C ++ 11 标记了覆盖explicit
关键字以防止它导致int转换,因为这样做可能导致标志集在写出来时最终折叠成0或1。如果您无法使用C ++ 11,请忽略该重载并将示例用法中的第一个条件重写为(myFlags & EFlagTwo) == EFlagTwo
。
[Flags]
属性可以正常工作,即:[Flags] enum class FlagBits{ Ready = 1, ReadMode = 2, WriteMode = 4, EOF = 8, Disabled = 16};