Using scoped enums for bit flags in C++

An enum X : int (C#) or enum class X : int (C++11) is a type that has a hidden inner field of int that can hold any value. In addition, a number of predefined constants of X are defined on the enum. It is possible to cast the enum to its integer value and vice versa. This is all true in both C# and C++11.

In C# enums are not only used to hold individual values, but also to hold bitwise combinations of flags, as per Microsoft’s recommendation. Such enums are (usually, but not necessarily) decorated with the [Flags] attribute. To make the lives of developers easier, the bitwise operators (OR, AND, etc…) are overloaded so that you can easily do something like this (C#):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>void M(NumericType flags);
M(NumericType.Sign | NumericType.ZeroPadding);
</code>
<code>void M(NumericType flags); M(NumericType.Sign | NumericType.ZeroPadding); </code>
void M(NumericType flags);

M(NumericType.Sign | NumericType.ZeroPadding);

I am an experienced C# developer, but have been programming C++ only for a couple of days now, and I am not known with the C++ conventions. I intend to use a C++11 enum in the exact same way as I was used to do in C#. In C++11 the bitwise operators on scoped enums are not overloaded, so I wanted to overload them.

This solicited a debate, and opinions seem to vary between three options:

  1. A variable of the enum type is used to hold the bit field, similar to C#:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>void M(NumericType flags);
    // With operator overloading:
    M(NumericType::Sign | NumericType::ZeroPadding);
    // Without operator overloading:
    M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)));
    </code>
    <code>void M(NumericType flags); // With operator overloading: M(NumericType::Sign | NumericType::ZeroPadding); // Without operator overloading: M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding))); </code>
    void M(NumericType flags);
    
    // With operator overloading:
    M(NumericType::Sign | NumericType::ZeroPadding);
    
    // Without operator overloading:
    M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)));
    

    But this would counter the strongly typed enum philosophy of C++11’s scoped enums.

  2. Use a plain integer if you want to store a bitwise combination of enums:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>void M(int flags);
    M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
    </code>
    <code>void M(int flags); M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)); </code>
    void M(int flags);
    
    M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
    

    But this would reduce everything to an int, leaving you with no clue as to which type you’re supposed to put in the method.

  3. Write a separate class that will overload operators and hold the bitwise flags in a hidden integer field:

    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    <code>class NumericTypeFlags {
    unsigned flags_;
    public:
    NumericTypeFlags () : flags_(0) {}
    NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {}
    //...define BITWISE test/set operations
    };
    void M(NumericTypeFlags flags);
    M(NumericType::Sign | NumericType::ZeroPadding);
    </code>
    <code>class NumericTypeFlags { unsigned flags_; public: NumericTypeFlags () : flags_(0) {} NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {} //...define BITWISE test/set operations }; void M(NumericTypeFlags flags); M(NumericType::Sign | NumericType::ZeroPadding); </code>
    class NumericTypeFlags {
        unsigned flags_;
    public:
        NumericTypeFlags () : flags_(0) {}
        NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {}
        //...define BITWISE test/set operations
    };
    
    void M(NumericTypeFlags flags);
    
    M(NumericType::Sign | NumericType::ZeroPadding);
    

    (full code by user315052)

    But then you have no IntelliSense or whatever support to hint you at the possible values.

I know this is a subjective question, but: What approach should I use? What approach, if any, is the most widely recognized in C++? What approach do you use when dealing with bit fields and why?

Of course since all three approaches work, I’m looking for factual and technical reasons, generally accepted conventions, and not simply personal preference.

For example, because of my C# background I tend to go with approach 1 in C++. This has the added benefit that my development environment can hint me on the possible values, and with overloaded enum operators this is easy to write and understand, and quite clean. And the method signature shows clearly what kind of value it expects. But most people here disagree with me, probably for good reason.

5

The simplest way is to provide the operator overloads yourself.
I am thinking of creating a macro to expand the basic overloads per type.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#include <type_traits>
enum class SBJFrameDrag
{
None = 0x00,
Top = 0x01,
Left = 0x02,
Bottom = 0x04,
Right = 0x08,
};
inline SBJFrameDrag operator | (SBJFrameDrag lhs, SBJFrameDrag rhs)
{
using T = std::underlying_type_t <SBJFrameDrag>;
return static_cast<SBJFrameDrag>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
inline SBJFrameDrag& operator |= (SBJFrameDrag& lhs, SBJFrameDrag rhs)
{
lhs = lhs | rhs;
return lhs;
}
</code>
<code>#include <type_traits> enum class SBJFrameDrag { None = 0x00, Top = 0x01, Left = 0x02, Bottom = 0x04, Right = 0x08, }; inline SBJFrameDrag operator | (SBJFrameDrag lhs, SBJFrameDrag rhs) { using T = std::underlying_type_t <SBJFrameDrag>; return static_cast<SBJFrameDrag>(static_cast<T>(lhs) | static_cast<T>(rhs)); } inline SBJFrameDrag& operator |= (SBJFrameDrag& lhs, SBJFrameDrag rhs) { lhs = lhs | rhs; return lhs; } </code>
#include <type_traits>

enum class SBJFrameDrag
{
    None = 0x00,
    Top = 0x01,
    Left = 0x02,
    Bottom = 0x04,
    Right = 0x08,
};

inline SBJFrameDrag operator | (SBJFrameDrag lhs, SBJFrameDrag rhs)
{
    using T = std::underlying_type_t <SBJFrameDrag>;
    return static_cast<SBJFrameDrag>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
    
inline SBJFrameDrag& operator |= (SBJFrameDrag& lhs, SBJFrameDrag rhs)
{
    lhs = lhs | rhs;
    return lhs;
}

(Note that type_traits is a C++11 header and std::underlying_type_t is a C++14 feature.)

8

Historically, I would always have used the old (weakly-typed) enumeration to name the bit constants, and just used the storage class explicitly to store the resulting flag. Here, the onus would be on me to make sure my enumerations fit in the storage type, and to keep track of the association between the field and it’s related constants.

I like the idea of strongly-typed enums, but I’m not really comfortable with the idea that variables of enumerated type may contain values that aren’t among that enumeration’s constants.

Eg, assuming the bitwise or has been overloaded:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>enum class E1 { A=1, B=2, C=4 };
void test(E1 e) {
switch(e) {
case E1::A: do_a(); break;
case E1::B: do_b(); break;
case E1::C: do_c(); break;
default:
illegal_value();
}
}
// ...
test(E1::A); // ok
test(E1::A | E1::B); // nope
</code>
<code>enum class E1 { A=1, B=2, C=4 }; void test(E1 e) { switch(e) { case E1::A: do_a(); break; case E1::B: do_b(); break; case E1::C: do_c(); break; default: illegal_value(); } } // ... test(E1::A); // ok test(E1::A | E1::B); // nope </code>
enum class E1 { A=1, B=2, C=4 };
void test(E1 e) {
    switch(e) {
    case E1::A: do_a(); break;
    case E1::B: do_b(); break;
    case E1::C: do_c(); break;
    default:
        illegal_value();
    }
}
// ...
test(E1::A); // ok
test(E1::A | E1::B); // nope

For your 3rd option, you need some boilerplate to extract the enumeration’s storage type. Assuming we want to force an unsigned underlying type (we can handle signed too, with a little more code):

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>template <size_t Size> struct IntegralTypeLookup;
template <> struct IntegralTypeLookup<sizeof(int64_t)> { typedef uint64_t Type; };
template <> struct IntegralTypeLookup<sizeof(int32_t)> { typedef uint32_t Type; };
template <> struct IntegralTypeLookup<sizeof(int16_t)> { typedef uint16_t Type; };
template <> struct IntegralTypeLookup<sizeof(int8_t)> { typedef uint8_t Type; };
template <typename IntegralType> struct Integral {
typedef typename IntegralTypeLookup<sizeof(IntegralType)>::Type Type;
};
template <typename ENUM> class EnumeratedFlags {
typedef typename Integral<ENUM>::Type RawType;
RawType raw;
public:
EnumeratedFlags() : raw() {}
EnumeratedFlags(EnumeratedFlags const&) = default;
void set(ENUM e) { raw |= static_cast<RawType>(e); }
void reset(ENUM e) { raw &= ~static_cast<RawType>(e); };
bool test(ENUM e) const { return raw & static_cast<RawType>(e); }
RawType raw_value() const { return raw; }
};
enum class E2: uint8_t { A=1, B=2, C=4 };
typedef EnumeratedFlags<E2> E2Flag;
</code>
<code>template <size_t Size> struct IntegralTypeLookup; template <> struct IntegralTypeLookup<sizeof(int64_t)> { typedef uint64_t Type; }; template <> struct IntegralTypeLookup<sizeof(int32_t)> { typedef uint32_t Type; }; template <> struct IntegralTypeLookup<sizeof(int16_t)> { typedef uint16_t Type; }; template <> struct IntegralTypeLookup<sizeof(int8_t)> { typedef uint8_t Type; }; template <typename IntegralType> struct Integral { typedef typename IntegralTypeLookup<sizeof(IntegralType)>::Type Type; }; template <typename ENUM> class EnumeratedFlags { typedef typename Integral<ENUM>::Type RawType; RawType raw; public: EnumeratedFlags() : raw() {} EnumeratedFlags(EnumeratedFlags const&) = default; void set(ENUM e) { raw |= static_cast<RawType>(e); } void reset(ENUM e) { raw &= ~static_cast<RawType>(e); }; bool test(ENUM e) const { return raw & static_cast<RawType>(e); } RawType raw_value() const { return raw; } }; enum class E2: uint8_t { A=1, B=2, C=4 }; typedef EnumeratedFlags<E2> E2Flag; </code>
template <size_t Size> struct IntegralTypeLookup;
template <> struct IntegralTypeLookup<sizeof(int64_t)> { typedef uint64_t Type; };
template <> struct IntegralTypeLookup<sizeof(int32_t)> { typedef uint32_t Type; };
template <> struct IntegralTypeLookup<sizeof(int16_t)> { typedef uint16_t Type; };
template <> struct IntegralTypeLookup<sizeof(int8_t)>  { typedef uint8_t Type; };

template <typename IntegralType> struct Integral {
    typedef typename IntegralTypeLookup<sizeof(IntegralType)>::Type Type;
};

template <typename ENUM> class EnumeratedFlags {
    typedef typename Integral<ENUM>::Type RawType;
    RawType raw;
public:
    EnumeratedFlags() : raw() {}
    EnumeratedFlags(EnumeratedFlags const&) = default;

    void set(ENUM e)   { raw |=  static_cast<RawType>(e); }
    void reset(ENUM e) { raw &= ~static_cast<RawType>(e); };
    bool test(ENUM e) const { return raw & static_cast<RawType>(e); }

    RawType raw_value() const { return raw; }
};
enum class E2: uint8_t { A=1, B=2, C=4 };
typedef EnumeratedFlags<E2> E2Flag;

This still doesn’t give you IntelliSense or autocompletion, but the storage type detection is less ugly than I originally expected.


Now, I did find an alternative: you can specify the storage type for a weakly-typed enumeration. It even has the same syntax as in C#

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>enum E4 : int { ... };
</code>
<code>enum E4 : int { ... }; </code>
enum E4 : int { ... };

Because it’s weakly-typed, and implicitly converts to/from int (or whatever storage type you choose), it feels less weird to have values which don’t match the enumerated constants.

The downside is that this is described as “transitional” …

NB. this variant adds its enumerated constants to both the nested and the enclosing scope, but you can work around this with a namespace:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>namespace E5 {
enum Enum : int { A, B, C };
}
E5::Enum x = E5::A; // or E5::Enum::A
</code>
<code>namespace E5 { enum Enum : int { A, B, C }; } E5::Enum x = E5::A; // or E5::Enum::A </code>
namespace E5 {
    enum Enum : int { A, B, C };
}
E5::Enum x = E5::A; // or E5::Enum::A

4

You can define type-safe enum flags in C++11 by using std::enable_if. This is a rudimentary implementation that may be missing some things:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>template<typename Enum, bool IsEnum = std::is_enum<Enum>::value>
class bitflag;
template<typename Enum>
class bitflag<Enum, true>
{
public:
constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;
constexpr bitflag() = default;
constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
constexpr bitflag(const bitflag& other) : bits(other.bits) {}
constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }
constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }
constexpr bool any() const { return bits.any(); }
constexpr bool all() const { return bits.all(); }
constexpr bool none() const { return bits.none(); }
constexpr operator bool() const { return any(); }
constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }
private:
std::bitset<number_of_bits> bits;
};
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
return bitflag<Enum>(left) ^ right;
}
</code>
<code>template<typename Enum, bool IsEnum = std::is_enum<Enum>::value> class bitflag; template<typename Enum> class bitflag<Enum, true> { public: constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits; constexpr bitflag() = default; constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {} constexpr bitflag(const bitflag& other) : bits(other.bits) {} constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; } constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; } constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; } constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; } constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; } constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; } constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; } constexpr bool any() const { return bits.any(); } constexpr bool all() const { return bits.all(); } constexpr bool none() const { return bits.none(); } constexpr operator bool() const { return any(); } constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); } constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); } constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); } private: std::bitset<number_of_bits> bits; }; template<typename Enum> constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right) { return bitflag<Enum>(left) | right; } template<typename Enum> constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right) { return bitflag<Enum>(left) & right; } template<typename Enum> constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right) { return bitflag<Enum>(left) ^ right; } </code>
template<typename Enum, bool IsEnum = std::is_enum<Enum>::value>
class bitflag;

template<typename Enum>
class bitflag<Enum, true>
{
public:
  constexpr const static int number_of_bits = std::numeric_limits<typename std::underlying_type<Enum>::type>::digits;

  constexpr bitflag() = default;
  constexpr bitflag(Enum value) : bits(1 << static_cast<std::size_t>(value)) {}
  constexpr bitflag(const bitflag& other) : bits(other.bits) {}

  constexpr bitflag operator|(Enum value) const { bitflag result = *this; result.bits |= 1 << static_cast<std::size_t>(value); return result; }
  constexpr bitflag operator&(Enum value) const { bitflag result = *this; result.bits &= 1 << static_cast<std::size_t>(value); return result; }
  constexpr bitflag operator^(Enum value) const { bitflag result = *this; result.bits ^= 1 << static_cast<std::size_t>(value); return result; }
  constexpr bitflag operator~() const { bitflag result = *this; result.bits.flip(); return result; }

  constexpr bitflag& operator|=(Enum value) { bits |= 1 << static_cast<std::size_t>(value); return *this; }
  constexpr bitflag& operator&=(Enum value) { bits &= 1 << static_cast<std::size_t>(value); return *this; }
  constexpr bitflag& operator^=(Enum value) { bits ^= 1 << static_cast<std::size_t>(value); return *this; }

  constexpr bool any() const { return bits.any(); }
  constexpr bool all() const { return bits.all(); }
  constexpr bool none() const { return bits.none(); }
  constexpr operator bool() const { return any(); }

  constexpr bool test(Enum value) const { return bits.test(1 << static_cast<std::size_t>(value)); }
  constexpr void set(Enum value) { bits.set(1 << static_cast<std::size_t>(value)); }
  constexpr void unset(Enum value) { bits.reset(1 << static_cast<std::size_t>(value)); }

private:
  std::bitset<number_of_bits> bits;
};

template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator|(Enum left, Enum right)
{
  return bitflag<Enum>(left) | right;
}
template<typename Enum>
constexpr typename std::enable_if<std::is_enum<Enum>::value, bitflag<Enum>>::type operator&(Enum left, Enum right)
{
  return bitflag<Enum>(left) & right;
}
template<typename Enum>
constexpr typename std::enable_if_t<std::is_enum<Enum>::value, bitflag<Enum>>::type operator^(Enum left, Enum right)
{
  return bitflag<Enum>(left) ^ right;
}

Note the number_of_bits can unfortunately not be filled in by the compiler, as C++ doesn’t have any way to do introspect the possible values of an enumeration.

Edit:
Actually I stand corrected, it is possible to get the compiler fill number_of_bits for you.

Note this can handle (wildly inefficiently) a non-continuous enum value range. Let’s just say it’s not a good idea to use the above with an enum like this or madness will ensue:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>enum class wild_range { start = 0, end = 999999999 };
</code>
<code>enum class wild_range { start = 0, end = 999999999 }; </code>
enum class wild_range { start = 0, end = 999999999 };

But all things considered this is a quite usable solution in the end. Doesn’t need any user-side bitfiddling, is type-safe and within its bounds, as efficient as it gets (I’m leaning strongly on std::bitset implementation quality here ;)).

3

I hate detest macros in my C++14 as much as the next guy, but I’ve taken to using this all over the place, and quite liberally too:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#define ENUM_FLAG_OPERATOR(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)
enum class T;
inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); }
ENUM_FLAG_OPERATOR(T,|)
ENUM_FLAG_OPERATOR(T,^)
ENUM_FLAG_OPERATOR(T,&)
enum class T
</code>
<code>#define ENUM_FLAG_OPERATOR(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) enum class T; inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); } ENUM_FLAG_OPERATOR(T,|) ENUM_FLAG_OPERATOR(T,^) ENUM_FLAG_OPERATOR(T,&) enum class T </code>
#define ENUM_FLAG_OPERATOR(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) 
enum class T; 
inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); } 
ENUM_FLAG_OPERATOR(T,|) 
ENUM_FLAG_OPERATOR(T,^) 
ENUM_FLAG_OPERATOR(T,&) 
enum class T

Making use as simple as

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ENUM_FLAGS(Fish)
{
OneFish,
TwoFish,
RedFish,
BlueFish
};
</code>
<code>ENUM_FLAGS(Fish) { OneFish, TwoFish, RedFish, BlueFish }; </code>
ENUM_FLAGS(Fish)
{
    OneFish,
    TwoFish,
    RedFish,
    BlueFish
};

And, as they say, the proof is in the pudding:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>ENUM_FLAGS(Hands)
{
NoHands = 0,
OneHand = 1 << 0,
TwoHands = 1 << 1,
LeftHand = 1 << 2,
RightHand = 1 << 3
};
Hands hands = Hands::OneHand | Hands::TwoHands;
if ( ( (hands & ~Hands::OneHand) ^ (Hands::TwoHands) ) == Hands::NoHands)
{
std::cout << "Look ma, no hands!" << std::endl;
}
</code>
<code>ENUM_FLAGS(Hands) { NoHands = 0, OneHand = 1 << 0, TwoHands = 1 << 1, LeftHand = 1 << 2, RightHand = 1 << 3 }; Hands hands = Hands::OneHand | Hands::TwoHands; if ( ( (hands & ~Hands::OneHand) ^ (Hands::TwoHands) ) == Hands::NoHands) { std::cout << "Look ma, no hands!" << std::endl; } </code>
ENUM_FLAGS(Hands)
{
    NoHands = 0,
    OneHand = 1 << 0,
    TwoHands = 1 << 1,
    LeftHand = 1 << 2,
    RightHand = 1 << 3
};

Hands hands = Hands::OneHand | Hands::TwoHands;
if ( ( (hands & ~Hands::OneHand) ^ (Hands::TwoHands) ) == Hands::NoHands)
{
    std::cout << "Look ma, no hands!" << std::endl;
}

Feel free to undefine any of the individual operators as you see fit, but in my highly-biased opinion, C/C++ is for interfacing with low-level concepts and streams, and you can pry these bitwise operators out of my cold, dead hands and I’ll fight you with all the unholy macros and bit-flipping spells I can conjure to keep them.

3

A short example of enum-flags below, looks pretty much like C#.

About the approach, in my opinion: less code, less bugs, better code.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#indlude "enum_flags.h"
ENUM_FLAGS(foo_t)
enum class foo_t
{
none = 0x00
,a = 0x01
,b = 0x02
};
ENUM_FLAGS(foo2_t)
enum class foo2_t
{
none = 0x00
,d = 0x01
,e = 0x02
};
int _tmain(int argc, _TCHAR* argv[])
{
if(flags(foo_t::a & foo_t::b)) {};
// if(flags(foo2_t::d & foo_t::b)) {}; // Type safety test - won't compile if uncomment
};
</code>
<code>#indlude "enum_flags.h" ENUM_FLAGS(foo_t) enum class foo_t { none = 0x00 ,a = 0x01 ,b = 0x02 }; ENUM_FLAGS(foo2_t) enum class foo2_t { none = 0x00 ,d = 0x01 ,e = 0x02 }; int _tmain(int argc, _TCHAR* argv[]) { if(flags(foo_t::a & foo_t::b)) {}; // if(flags(foo2_t::d & foo_t::b)) {}; // Type safety test - won't compile if uncomment }; </code>
#indlude "enum_flags.h"

ENUM_FLAGS(foo_t)
enum class foo_t
    {
     none           = 0x00
    ,a              = 0x01
    ,b              = 0x02
    };

ENUM_FLAGS(foo2_t)
enum class foo2_t
    {
     none           = 0x00
    ,d              = 0x01
    ,e              = 0x02
    };  

int _tmain(int argc, _TCHAR* argv[])
    {
    if(flags(foo_t::a & foo_t::b)) {};
    // if(flags(foo2_t::d & foo_t::b)) {};  // Type safety test - won't compile if uncomment
    };

ENUM_FLAGS(T) is a macro, defined in enum_flags.h (less then 100 lines, free to use with no restrictions).

7

Typically you’d define a set of integer values that correspond to single-bit set binary numbers, then add them together. This is the way C programmers usually do it.

So you’d have (using the bitshift operator to set the values, eg 1 << 2 is the same as binary 100)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#define ENUM_1 1
#define ENUM_2 1 << 1
#define ENUM_3 1 << 2
</code>
<code>#define ENUM_1 1 #define ENUM_2 1 << 1 #define ENUM_3 1 << 2 </code>
#define ENUM_1 1
#define ENUM_2 1 << 1
#define ENUM_3 1 << 2

etc

In C++ you have more options, define a new type rather that is an int (use typedef) and similarly set values as above; or define a bitfield or a vector of bools. The last 2 are very space efficient and make a lot more sense for dealing with flags. A bitfield has the advantage of giving you type checking (and therefore intellisense).

I’d say (obviously subjective) that a C++ programmer should use a bitfield for your problem, but I tend to see the #define approach used by C programs a lot in C++ programs.

I suppose the bitfield is the closest to C#’s enum, why C# tried to overload an enum to be a bitfield type is weird – an enum should really be a “single-select” type.

3

There is yet another way to skin the cat:

Instead of overloading the bit operators, at least some might prefer to just add a 4 liner to help you circumvent that nasty restriction of scoped enums:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>#include <cstdio>
#include <cstdint>
#include <type_traits>
enum class Foo : uint16_t { A = 0, B = 1, C = 2 };
// ut_cast() casts the enum to its underlying type.
template <typename T>
inline auto ut_cast(T x) -> std::enable_if_t<std::is_enum_v<T>,std::underlying_type_t<T>>
{
return static_cast<std::underlying_type_t<T> >(x);
}
int main(int argc, const char*argv[])
{
Foo foo{static_cast<Foo>(ut_cast(Foo::B) | ut_cast(Foo::C))};
Foo x{ Foo::C };
if(0 != (ut_cast(x) & ut_cast(foo)) )
puts("works!");
else
puts("DID NOT WORK - ARGHH");
return 0;
}
</code>
<code>#include <cstdio> #include <cstdint> #include <type_traits> enum class Foo : uint16_t { A = 0, B = 1, C = 2 }; // ut_cast() casts the enum to its underlying type. template <typename T> inline auto ut_cast(T x) -> std::enable_if_t<std::is_enum_v<T>,std::underlying_type_t<T>> { return static_cast<std::underlying_type_t<T> >(x); } int main(int argc, const char*argv[]) { Foo foo{static_cast<Foo>(ut_cast(Foo::B) | ut_cast(Foo::C))}; Foo x{ Foo::C }; if(0 != (ut_cast(x) & ut_cast(foo)) ) puts("works!"); else puts("DID NOT WORK - ARGHH"); return 0; } </code>
#include <cstdio>
#include <cstdint>
#include <type_traits>

enum class Foo : uint16_t { A = 0, B = 1, C = 2 };

// ut_cast() casts the enum to its underlying type.
template <typename T>
inline auto ut_cast(T x) -> std::enable_if_t<std::is_enum_v<T>,std::underlying_type_t<T>>
{
    return static_cast<std::underlying_type_t<T> >(x);
}

int main(int argc, const char*argv[])
{
   Foo foo{static_cast<Foo>(ut_cast(Foo::B) | ut_cast(Foo::C))};
   Foo x{ Foo::C };
   if(0 != (ut_cast(x) & ut_cast(foo)) )
       puts("works!");
    else 
        puts("DID NOT WORK - ARGHH");
   return 0;
}

Granted, you have to type the ut_cast() thing each time, but on the up side, this yields more readable code, in the same sense as using static_cast<>() does, compared to implicit type conversion or operator uint16_t() kind of things.

And let’s be honest here, using type Foo as in the code above has its dangers:

Somewhere else someone might do a switch case over variable foo and not expect that it holds more than one value…

So littering the code with ut_cast() helps alert readers that something fishy is going on.

Instead of doing all this work, wouldn’t it be much easier to use a struct of bit fields?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>struct MyFlags {
uint8_t flagOne:1;
uint8_t flagTwo:1;
uint8_t flagThree:1;
uint8_t flagFour:1;
uint8_t flagFive:1;
uint8_t flagSix:1;
uint8_t flagSeven:1;
uint8_t flagEight:1;
};
</code>
<code>struct MyFlags { uint8_t flagOne:1; uint8_t flagTwo:1; uint8_t flagThree:1; uint8_t flagFour:1; uint8_t flagFive:1; uint8_t flagSix:1; uint8_t flagSeven:1; uint8_t flagEight:1; }; </code>
struct MyFlags {
    uint8_t flagOne:1;
    uint8_t flagTwo:1;
    uint8_t flagThree:1;
    uint8_t flagFour:1;
    uint8_t flagFive:1;
    uint8_t flagSix:1;
    uint8_t flagSeven:1;
    uint8_t flagEight:1;
};

and then you can set/test it as

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>MyFlags flags = {};
flags.flagThree = true;
</code>
<code>MyFlags flags = {}; flags.flagThree = true; </code>
MyFlags flags = {};

flags.flagThree = true;

? Of course that won’t help if you need to extract the raw number, as it seems the standard doesn’t actually guarantee a layout (though at least Apple platforms seem to lay it out as you’d expect).

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật