How to use C++11 enum class for flags
You need to write your own overloaded operator|
(and presumably operator&
etc.).
Flags operator|(Flags lhs, Flags rhs)
{
return static_cast<Flags>(static_cast<char>(lhs) | static_cast<char>(rhs));
}
Conversion of an integer to an enumeration type (scoped or not) is well-defined as long as the value is within the range of enumeration values (and UB otherwise; [expr.static.cast]/p10). For enums with fixed underlying types (this includes all scoped enums; [dcl.enum]/p5), the range of enumeration values is the same as the range of values of the underlying type ([dcl.enum]/p8). The rules are trickier if the underlying type is not fixed - so don't do it :)
How does one use an enum class as a set of flags?
It is certainly possible to use enum class
es for bitmaps. It is, unfortunately, a bit painful to do so: You need to define the necessary bit operations on your type. Below is an example how this could look like. It would be nice if the enum class
es could derive from some other type which could live in a suitable namespace defining the necessary operator boilerplate code.
#include <iostream>
#include <type_traits>
enum class bitmap: unsigned char
{
a = 0x01,
b = 0x02,
c = 0x04
};
bitmap operator& (bitmap x, bitmap y)
{
typedef std::underlying_type<bitmap>::type uchar;
return bitmap(uchar(x) & uchar(y));
}
bitmap operator| (bitmap x, bitmap y)
{
typedef std::underlying_type<bitmap>::type uchar;
return bitmap(uchar(x) | uchar(y));
}
bitmap operator^ (bitmap x, bitmap y)
{
typedef std::underlying_type<bitmap>::type uchar;
return bitmap(uchar(x) ^ uchar(y));
}
bool test(bitmap x)
{
return std::underlying_type<bitmap>::type(x);
}
int main()
{
bitmap v = bitmap::a | bitmap::b;
if (test(v & bitmap::a)) {
std::cout << "a ";
}
if (test(v & bitmap::b)) {
std::cout << "b ";
}
if (test(v & bitmap::c)) {
std::cout << "c ";
}
std::cout << '\n';
}
How to use enums as flags in C++?
The "correct" way is to define bit operators for the enum, as:
enum AnimalFlags
{
HasClaws = 1,
CanFly = 2,
EatsFish = 4,
Endangered = 8
};
inline AnimalFlags operator|(AnimalFlags a, AnimalFlags b)
{
return static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));
}
Etc. rest of the bit operators. Modify as needed if the enum range exceeds int range.
c++: OR operator: enum vs enum class?
enum eDogType
values are processed as int
values, where enum class eDogType
values are not (they are processed as values of type eDogType
).
So in the first case, the operator | (int, int)
is used, whereas in the second case, the operator | (eDogType, eDogType)
is needed (but not found).
#include <iostream>
enum class eDogType
{
eHusk = 0,
eGold,
eAus,
eGerm,
ePud
};
int main()
{
eDogType eDog1 = eDogType::eAus;
eDogType eDog2 = eDogType::eGerm;
eDogType eDog = static_cast<eDogType>(static_cast<int>(eDog1) | static_cast<int>(eDog2));
std::cout << "Hello World: " << static_cast<int>(eDog) << "\n";
return(0);
}
C++ enum flags vs bitset
Do you compile with optimization on? It is very unlikely that there is a 24x speed factor.
To me, bitset is superior, because it manages space for you:
- can be extended as much as wanted. If you have a lot of flags, you may run out of space in the
int
/long long
version. - may take less space, if you only use just several flags (it can fit in an
unsigned char
/unsigned short
- I'm not sure that implementations apply this optimization, though)
Bitwise operations in Enumarators
Is the approach correct and how can we remove the compilation error?
The approach is subject to problems. If you work with your variables carefully, you can get by with using the enum
.
The line
perms &= ~Permissions::Executable;
is equivalent to
perms = perms & ~Permissions::Executable;
The cause of the compiler error is that the bitwise operators result in an int
and you are trying to assign an int
to an enum
without a cast.
You'll have to use a cast just like you did with the first operation to get rid of the compiler error.
perms = static_cast<Permissions>(perms & ~Permissions::Executable);
Update, in response to OP's comment
The value Readable | Writable
is 0x6
, which does not correspond to the value of any of the tokens in the enum
.
Hence, if you use:
Permissions p1 = Permissions::Readable;
Permissions p2 = Permissions::Writable;
Permissions p3 = static_cast<Permissions>(p1 | p2);
you will have a case where the value of p3
does not match any of the known tokens. If you have if
/else
blocks or switch
statements that expect the values of all variables of type Permissions
to be one of the known tokens, you will notice unexpected behavior in your code.
Related Topics
Why Doesn't Reinterpret_Cast Force Copy_N for Casts Between Same-Sized Types
Inserting into a Vector at the Front
How to Find an Official Reference Listing the Operation of Sse Intrinsic Functions
Order of Evaluation of Function Parameters
Where Would You Use a Friend Function VS. a Static Member Function
Acquire/Release Versus Sequentially Consistent Memory Order
Why Are Forward Declarations Necessary
How Does C++ Preprocessors Work
Removing Watermark Out of an Image Using Opencv
Why Does a C++ Friend Class Need a Forward Declaration Only in Other Namespaces
Familiar Template Syntax for Generic Lambdas
In Cmake, How to Test If the Compiler Is Clang
Should I Pass a Shared_Ptr by Reference
General Rules of Passing/Returning Reference of Array (Not Pointer) To/From a Function
How to Generate Random Numbers in C++
Differencebetween Cout, Cerr, Clog of iOStream Header in C++? When to Use Which One