Can you use bitwise operators with enum classes without casting?

3.3k views Asked by At

I like to use enum classes, but I use them as flags sometimes and I have to constantly cast to int if I want to use a bitwise operator. Is there a way to do this without casting? I don't think you can define the operators for them?

If I have functions that take an enum class, do I have to do this?

enum class Flags { FLAG1, FLAG2, FLAG3};

void setFlags(Flags flags){}

int main()
{
      setFlags((Flags)((int)Flags::FLAG1 | (int)Flags::FLAG2 | (int)Flags::FLAG3));
}
2

There are 2 answers

0
Tony Tannous On

The class after the enum specifies that an enumeration is strongly typed and that its enumerators are scoped. Beware, enum class has only assignment, initialization and comparisons defined by default. Nevertheless, an enumeration is user-defined type, as such, you can define operators for it.


If you don't want to explicitly qualify enumerator names and want enumerator values to be ints (without the need for an explicit conversion), you can remove the class from enum class to get "plain" enum. Enumerators are exported to the surrounding scope to evade name collisions, you can wrap with namespace.

#include <iostream>

namespace Flags {
    enum : int 
    {
        bit_1 = 0x1,
        bit_2 = 0x2
    };
}

int main()
{
    int num = 11;
    if (num & Flags::bit_1)
        std::cout << "lsb is on!\n";
    else 
        std::cout << "lsb is off!\n";
    return 0;
}

References:

  • A Tour of C++ Second edition by Bjarne Stroustrup
0
NutCracker On

If you don't want to overload operators on scoped enums yourself, why not using one of libraries that do that for you.

For example:

I have created such library myself - bitflags (it's not the best but does what I want) where you can create your flags by just specifying the following:

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
    FLAG(flag_c)
END_BITFLAGS(Flags)

and then you can do:

int main() {
    Flags flags = Flags::flag_a | Flags::flag_b;

    if (flags & Flags::flag_a) {
        std::cout << "flag_a is set" << std::endl;
    } else {
        std::cout << "flag_a is not set" << std::endl;
    }

    flags.toggle(Flags::flag_a);

    // ...

    return 0;
}

Notice that you don't need to specify the type for your flags because the minimum size type is being used automatically, and, furthermore, you don't need to specify values of your flags. They are assigned automatically too.