How to use C++11 enum class for flags

后端 未结 5 1217
面向向阳花
面向向阳花 2020-12-06 17:52

Say I have such a class:

enum class Flags : char
{
    FLAG_1 = 1;
    FLAG_2 = 2;
    FLAG_3 = 4;
    FLAG_4 = 8;
};

Now can I have a vari

相关标签:
5条回答
  • 2020-12-06 18:00

    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 :)

    0 讨论(0)
  • 2020-12-06 18:00

    The code in question doesn't compile. But you can do something like this,

    enum class Flags : char
    {
        FLAG_1 = 1,
        FLAG_2 = 2,
        FLAG_3 = 4,
        FLAG_4 = 8,
    };
    
    int main() {
        Flags f = static_cast<Flags>(7);
        Flags f1 = static_cast<Flags>( static_cast<char>(Flags::FLAG_1) | static_cast<char>(Flags::FLAG_2) | static_cast<char>(Flags::FLAG_3) );
        return 0;
    }
    

    and it works

    0 讨论(0)
  • 2020-12-06 18:07

    At this point, It probably makes sense to define your own class to handle this.

     /** Warning: Untested code **/
     struct Flag {
    
         static Flag Flag_1;
         static Flag Flag_2;
         static Flag Flag_3;
         static Flag Flag_4;
    
         Flag operator = (Flag);
     private:
         char const value;
     };
    
     Flag operator | (Flag, Flag); 
    
    0 讨论(0)
  • 2020-12-06 18:08

    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.

    0 讨论(0)
  • 2020-12-06 18:16

    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.

    0 讨论(0)
提交回复
热议问题