This is probably simple but I'm not getting it right. I have a "bitmask" enum which has a value all
that indicates that all bits are set. However, I can't get it to flip all bits using ~0. The following error appears:
<source>:11:16: error: enumerator value '-1' is outside the range of underlying type 'uint_fast8_t' {aka 'unsigned char'}
11 | all = ~0x0,
|
Which is strange because it should actually fit into uint8_t no? Here is my code (godbolt):
#include <iostream>
int main()
{
enum mask_t : uint_fast8_t {
first = 0x1,
second = 0x2,
all = ~0x0,
} mask;
mask = all;
}
By default, 0x0
is of type int
. So if you try to flip all the bits you'll get -1
which can't be assigned to the type your enumeration was defined to.
Even if you use a suffix for that literal value, like u
for example. To indicate that the literal value is of unsigned type. As in ~0x0u
. You'd get the maximum of the unsigned int
type. Which exceeds the range of the 8-bit integer type you're using. So this doesn't work either.
So you need to tell the language that you want the literal value to be of the type you need first. That can be achieved with a static_cast
as demonstrated in other answers:
static_cast<uint_fast8_t>( ~0x0 )
But using hardcoded types and values can get in the way sometimes if you decide to change the type of the enum later. So if you have c++14 available. You can use the std::underlying_type
type-trait and make a generic utility like:
template < class T > constexpr std::underlying_type_t< T > enum_max_v = ~static_cast< std::underlying_type_t< T > >(0);
// If you have c++17 available with the inline keyword
// template < class T > inline constexpr std::underlying_type_t< T > enum_max_v = ~static_cast< std::underlying_type_t< T > >(0);
And then used like:
enum mask_t : uint_fast8_t {
first = 0x1,
second = 0x2,
all = enum_max_v< mask_t >,
} mask;
Now you don't have to care about the underlying type of the enumeration.
You can even use std::numeric_limits
if you want the right values instead of relying on flipping bits:
template < class T > constexpr std::underlying_type_t< T > enum_max_v = std::numeric_limits< std::underlying_type_t< T > >::max();
Sky is the limit.