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:
bool
as the underlying type ?Thanks in advance.
If bool
is the underlying type of X
, then std::underlying_type_t<X>
is bool
.
Variables of type bool
and enum
s with bool
underlying type only have two valid states; 0
and 1
.
Variables of type uint8_t
and enum
s 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 bool
s or enum
s 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.