Reputation: 7954
I have several flag-like enumerations, in C++. For example:
enum some_state {
state_normal = 1 << 0,
state_special = 1 << 1,
state_somethingelse = 1 << 2,
state_none = 0,
};
some_state var1;
Now on using bit operators like &
or |
, I get compiler errors. I know I can overload operator |
et.al. for enums, but I hate to do that again for each and every enum. Is there a nice way to reuse the operator overloads?
Upvotes: 1
Views: 976
Reputation: 7954
I tried and searched, and I think the best solution is a #define. Based on something I found:
#define FLAGS(T) \
inline T operator |(const T s, const T e) { return (T)((unsigned)s | e); } \
inline T &operator |=(T &s, const T e) { return s = s | e; } \
inline T operator &(const T s, const T e) { return (T)((unsigned)s & e); } \
inline T &operator &=(T &s, const T e) { return s = s & e; } \
inline T operator ^(const T s, const T e) { return (T)((unsigned)s ^ e); } \
inline T &operator ^=(T &s, const T e) { return s = s ^ e; } \
inline T operator ~(const T s) { return (T)~(unsigned)s; }
This can be used like:
enum some_state {
state_normal = 1 << 0,
state_special = 1 << 1,
state_somethingelse = 1 << 2,
state_none = 0,
};
FLAGS(some_state)
some_state var1;
For Visual Studio one might need this to silence some warnings:
#pragma warning(disable: 4505) // '*' : unreferenced local function has been removed
In fact, the Windows SDK has the DEFINE_ENUM_FLAG_OPERATORS
macro to do just that.
A different approach is a wrapper class like DEF_ENUM_FLAGS_TYPE
uses.
Or use something like the LLVM_MARK_AS_BITMASK_ENUM
macro. You might need a recent compiler though.
Upvotes: 4
Reputation: 49311
Use an existing template library such as bitwise-enum to provide the operations rather than writing your own.
Upvotes: 2
Reputation: 146910
enum some_state {
state_normal = 1 << 0,
state_special = 1 << 1,
state_somethingelse = 1 << 2,
state_none = 0,
};
int main() {
some_state var1 = state_normal;
some_state var2 = state_special;
unsigned int var3 = var1 | var2;
}
Works fine for me. The reason that you can't use |, & etc without overloading is because the compiler can't guarantee the the result of var1 | var2 is a valid value in the enum. If you want to take shifted flags, you need to take an integral type, not the enum type. This is used all the time in professional headers like Direct3D.
Upvotes: 5