Any benefits to declare an enum class underlying type bool?

600 views Asked by At

In the library I am currently developing, I have this little thing:

enum class BoolMode : uint8_t
{
    TrueIfFalse = 0,
    TrueIfTrue  = 1
};

This is a tiny helper used to easily produce reversible condition checks, while only having to create a single implementation that's easy to write and to read...

For this helper to be effectively easy to use, I had to define the comparison operator for bool (obviously). I did it like that:

inline constexpr bool operator ==(const bool boolValue, const BoolMode mode) noexcept
{
    return (boolValue == static_cast<const bool>(mode));
}

inline constexpr bool operator !=(const bool boolValue, const BoolMode mode) noexcept
{
    return (boolValue != static_cast<const bool>(mode));
}

inline constexpr bool operator ==(const BoolMode mode, const bool boolValue) noexcept
{
    return (boolValue == static_cast<const bool>(mode));
}

inline constexpr bool operator !=(const BoolMode mode, const bool boolValue) noexcept
{
    return (boolValue != static_cast<const bool>(mode));
}

I was wondering if there would have any benefits to define BoolMode this way:

enum class BoolMode : bool
{
    TrueIfFalse = false,
    TrueIfTrue  = true
};

As it does not spare the effort to have to define the comparison operators anyway, I don't see what the best option would be...

Questions:

  • What is the purpose to use bool as the underlying type ?
  • Is there concrete examples of the use of it ?
  • Is there anything in this code to which I should be aware of ?
  • Any clues and/or suggestions to improve the code ?

Thanks in advance.

1

There are 1 answers

1
Yakk - Adam Nevraumont On BEST ANSWER

If bool is the underlying type of X, then std::underlying_type_t<X> is bool.

Variables of type bool and enums with bool underlying type only have two valid states; 0 and 1.

Variables of type uint8_t and enums with uint8_t underlying type has 256 valid states; 0 through 255.

Both a compiler, and metaprogramming, can be aware of this difference. A custom notstd::optional could use the fact that 3 is not a valid bool to make notstd::optional<bool> take up a single byte (its value would be 0 for false, 1 for true and 3 for nullopt).

This could also be used to smart-pack bools or enums with bool underlying type into bit-fields when serialized.

In theory, the assembly generated for == when bool is the underlying type could do a bit comparison instead of zero or non-zero byte check. I could imagine platforms where that is faster. Meanwhile, if uint8_t was the underlying type, a non-zero value anywhere in the enum means it maps to true when cast to bool.

None of these issues are likely.