Bitfields and strongly-typed enums

Something is wrong with the following code, can you spot what it is? (If in doubt, try compiling it.)

enum class Color { red = 1, green = 2, blue =  4 };
auto yellow = Color::red | Color::green;

As you may have found out, the compiler complains with a message such as: error: no match for 'operator|' (operand types are 'Color' and 'Color'). The simplistic solution is to remove the class keyword, and use the “plain” enum type, where the enumerators are implicitly convertible to and from int.

Alternatively we could grab the bull by the horns and try to define operator| (bitwise-or) for Color. The language allows this, but first we must find a way of extracting a type that can be operated upon, from the enum class definition. Luckily, the Standard Library comes to our rescue with the utility underlying_type<T> found in the <type_traits> header. (Note that we should not just assume that this type is int as it can be any integral or boolean type; interestingly the ability to set the underlying type has been backported to plain enum in Modern C++.)

So get ready for some casts, three in total – two from the Color parameters to the underlying type, and one back to Color for the return type. Here is the complete function (which needs both the <type_traits> header and enum class definition from before):

constexpr Color operator| (Color lhs, Color rhs) {
    using underlying_t = typename std::underlying_type<Color>::type;

    return static_cast<Color>(
        | static_cast<underlying_t>(rhs)

This function can be used to define operator| for any other enum class by changing the five occurrences of Color, thus enabling use as a bitfield. Here it has been declared constexpr so that these bitfields can be calculated for use at compile-time. If you choose to use this method, the important thing to remember is all those static_casts which ensure the bitwise-or operation cannot lose precision. It is of course possible to define other operators such as & (bitwise-and) and ~ (bitwise-complement) using similar code.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s