Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

People also ask

Can enum be Boolean?

Prefer Enums and Avoid Booleans An enumerator is a data type consisting of a set of named values that can be used in a type-safe way. While it may not look as simple as a boolean, using an enum or other user-defined type helps us avoid setting up complicated if statements with multiple branches.

Can we declare enum inside method?

We can an enumeration inside a class. But, we cannot define an enum inside a method. If you try to do so it generates a compile time error saying “enum types must not be local”.

What is the use of enum class?

You should use enum types any time you need to represent a fixed set of constants. That includes natural enum types such as the planets in our solar system and data sets where you know all possible values at compile time—for example, the choices on a menu, command line flags, and so on.

Can I declare enum in class?

Yes, we can define an enumeration inside a class. You can retrieve the values in an enumeration using the values() method.


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) {
  ...
}

Is it possible to specify a custom function to evaluate a class enum in a boolean context?

Yes, but not automatically. Manually calling a function is still more elegant than the other alternatives presented.

Simply pick a nice function name, such as any, and implement it. Overload resolution will make sure your function plays well with all others.

bool any( E arg )
    { return arg != E::none; }

...

if ( any( flags ) ) {
    ...

Looks nice enough to me.


Update: if you want this to apply to several enumeration types, it can be templated:

template< typename enum_type > // Declare traits type
struct enum_traits {}; // Don't need to declare all possible traits

template<>
struct enum_traits< E > { // Specify traits for "E"
    static constexpr bool has_any = true; // Only need to specify true traits
};

template< typename enum_type > // SFINAE makes function contingent on trait
typename std::enable_if< enum_traits< enum_type >::has_any,
    bool >::type
any( enum_type e )
    { return e != enum_type::none; }

I've been using this sort of mechanism for other things and never encountered any side effects or issues :v) .

You could skip the trait and set the SFINAE condition to something like enum_type::none == enum_type::none, to merely check for the presence of none and the equality operator, but that would be less explicit and safe.


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.


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.


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.