How to use C++11 enum class for flags

Solution 1:

You need to write your own overloaded operator| (and presumably operator& etc.).

Flags operator|(Flags lhs, Flags rhs) 
{
    return static_cast<Flags>(static_cast<char>(lhs) | static_cast<char>(rhs));
}

Conversion of an integer to an enumeration type (scoped or not) is well-defined as long as the value is within the range of enumeration values (and UB otherwise; [expr.static.cast]/p10). For enums with fixed underlying types (this includes all scoped enums; [dcl.enum]/p5), the range of enumeration values is the same as the range of values of the underlying type ([dcl.enum]/p8). The rules are trickier if the underlying type is not fixed - so don't do it :)

Solution 2:

It's maybe better to make use of std::underlying_type instead of hard-coding char type.

Flags operator|(Flags lhs, Flags rhs) {
    return static_cast<Flags>(
        static_cast<std::underlying_type<Flags>::type>(lhs) |
        static_cast<std::underlying_type<Flags>::type>(rhs)
    );
}

Now, you can change the underlying type of your enumeration without needing to update that type in every bitwise operator overload.

Solution 3:

Please don't do this. If you need to do this, enum classs probably aren't what you need.

@T.C. showed you how to do it so long as you specify underlying type, but you will run into places where your program does things it just shouldn't.

An example is where you use a switch and have a case for every defined enum value.

e.g.

enum class my_enum: unsigned int{
    first = 1,
    second = 2,
    third = 4,
    fourth = 8
};

int main(){
    auto e = static_cast<my_enum>(static_cast<unsigned int>(my_enum::first) | static_cast<unsigned int>(my_enum::second));

    switch(e){
        case my_enum::first:
        case my_enum::second:
        case my_enum::third:
        case my_enum::fourth:
            return 0;
    }

    std::cout << "Oh, no! You reached a part of the program you weren't meant to!\n";
    return 1;
}

Will output:

Oh, no! You reached a part of the program you weren't meant to!

then return the error code 1.

Which is also an example of why you should always have a default case, of course, but that isn't my point.

Of course, you could argue that so long as the user of the enum class never directly uses the value other than passing to a function; it would be a good way of restricting the values of a bitset. But I've always been a little too trustworthy and find std::uint[n]_t and some constexpr variables the best way (if a user sets an invalid bit it simply does nothing).

What you're doing just isn't really suitable for enum class, because it defeats the purpose of having a scoped enumeration. You can no longer enumerate the values if you set it to an undefined one.