Michel de Ruiter
Michel de Ruiter

Reputation: 7954

How to reuse enum operator overloads in C++?

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

Answers (3)

Michel de Ruiter
Michel de Ruiter

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

Pete Kirkham
Pete Kirkham

Reputation: 49311

Use an existing template library such as bitwise-enum to provide the operations rather than writing your own.

Upvotes: 2

Puppy
Puppy

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

Related Questions