How can I use an enum class in a boolean context?

后端 未结 7 1900
醉酒成梦
醉酒成梦 2021-01-07 15:59

I have some generic code that works with flags specified using C++11 enum class types. At one step, I\'d like to know if any of the bits in the flag are set. Cu

相关标签:
7条回答
  • 2021-01-07 16:39

    A short example of enum-flags below.

    #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).

    0 讨论(0)
  • 2021-01-07 16:41

    Like @RMatin says. But you could overload operator!

    bool operator!(E e) {
      return e == static_cast<E>(0);
    }
    

    So that you can use the !!e idiom

    if(!!e) {
      ...
    }
    
    0 讨论(0)
  • 2021-01-07 16:46
    struct Error {
        enum {
            None        = 0,
            Error1      = 1,
            Error2      = 2,
        } Value;
    
        /* implicit */ Error(decltype(Value) value) : Value(value) {}
    
        explicit operator bool() {
            return Value != Error::None;
        }
    };
    
    inline bool operator==(Error a, Error b) {
        return a.Value == b.Value;
    }
    
    inline bool operator!=(Error a, Error b) {
        return !(a == b);
    }
    

    enum has no overloaded operator for now, so wrap it in a class or struct.

    0 讨论(0)
  • 2021-01-07 16:46

    If you have a flags field (ie: a bitfield) I would strongly advise you not to use enum class for bitfields.

    Strongly typed enums exist to be, well, strongly typed. It makes the enumerators into something more than just named constant integers the way regular enums are. The idea is that, if you have a variable of an enum class type, then its contents should always exactly match one of the enumerator values. That's why there is no implicit conversion from or to integer types.

    But that's not what you're doing. You're taking a bitfield, which is a composition of enumerator values. That composition is not itself any one of those values; it's a combination of them. Therefore, you're lying when you say that you're taking the enum class type; you're really just taking an unsigned integer that might be one of the enum class enumerators.

    For example:

    enum class Foo
    {
      First   = 0x01,
      Second  = 0x02,
      Third   = 0x04,
    };
    
    Foo val = Foo::First | Foo::Second;
    

    val in this case does not contain First, Second, or Third. You've lost strong typing, because it doesn't contain any of the types.

    enum class values cannot be implicitly converted to bool; they cannot be implicitly converted to integers; and they cannot implicitly have most math operations performed on them. They are opaque values.

    And thus they are inappropriate for use as bitfields. Attempting to use enum class in such an inappropriate way will only lead to a lot of casting. Just use a regular old enum and save yourself the pain.

    0 讨论(0)
  • 2021-01-07 16:50

    No, not like that. Conversion operators must be members, and enums cannot have members. I think the best you can do is comparison with none, or, if there isn't a none enumerator, wrap the static_cast in a function.

    0 讨论(0)
  • 2021-01-07 16:53

    I usually overload the unary + operator for flag-like enum classes, so that i can do the following:

    #define ENUM_FLAGS (FlagType, UnderlyingType)                           \
        /* ... */                                                           \
        UnderlyingType operator+(const FlagType &flags) {                   \
              return static_cast<UnderlyingType>(flags)                     \
        }                                                                   \
        /* ... */                                                           \
        FlagType operator&(const FlagType &lhs, const FlagType &rhs) {      \
              return static_cast<FlagType>(+lhs & +rhs)                     \
        }                                                                   \
        /* ... */                                                           \
        FlagType &operator|=(FlagType &lhs, const FlagType &rhs) {          \
              return lhs = static_cast<FlagType>(+lhs | +rhs)               \
        }                                                                   \
        /* ... */                                                           \
        /***/
    
    // ....
    
    enum class Flags: std::uint16_t {
        NoFlag  = 0x0000,
        OneFlag = 0x0001,
        TwoFlag = 0x0002,
        // ....      
        LastFlag = 0x8000
    };
    
    ENUM_FLAGS(Flags, std::uint16_t)
    
    auto flagVar = Flags::NoFlag;
    
    // ...
    
    flagVar |= Flags::OneFlag;
    
    // ...
    
    if (+(flagVar & Flags::OneFlag)) {
        /// ...
    }
    
    0 讨论(0)
提交回复
热议问题