現在受け入れられているエイドロンの答えは危険すぎると思います。コンパイラのオプティマイザは、列挙型で可能な値について想定を行う可能性があり、無効な値でガベージが返される可能性があります。そして通常、フラグ列挙型で可能なすべての順列を定義することは誰も望んでいません。
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
また、2番目のテンプレートパラメータ(つまり、)を使用して、バイナリ安定型列挙型(C ++ 11など)の基になる型をオーバーライドすることもできますtypedef SafeEnum<enum TFlags_,uint8_t> TFlags;
。
operator bool
オーバーライドをC++11のキーワードでマークしてexplicit
、int変換が発生しないようにしました。これは、フラグのセットを書き出すときに0または1に折りたたまれる可能性があるためです。C ++ 11を使用できない場合は、そのオーバーロードを省略し、使用例の最初の条件を。として書き直します(myFlags & EFlagTwo) == EFlagTwo
。