views:

95

answers:

3

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 compilers 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?

+1  A: 

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
Michel de Ruiter
Nice, you answered your own question! :)
Akanksh
If you really want to do that, inline rather than static would have better semantics for the linker - to a first approximation, static means it gets used in this file and only in this file, inline means it can be defined in multiple files.
Pete Kirkham
@Akanksh: do you have something against it?
Michel de Ruiter
@Michel de Ruiter : Oh no, sorry if it felt that way, I just have a lot of respect for people who try to find solutions themselves rather than just putting it up here and waiting for a response. My last comment was meant in the best possible way, I apologize if it seemed otherwise.
Akanksh
@Pete Kirkham: thanks, I'll change `static` to `inline`!
Michel de Ruiter
+6  A: 
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.

DeadMG
Thanks for explaining. I don't think the compiler can ever guarantee that the result of var1 | var2 is a valid value in the enum though, as var1 and var2 can contain any value. For readability I wanted to declare var3 as some_state as well, that's why I needed the operator overloads. In addition, the #define 'annotates' the enum as containing flags.
Michel de Ruiter
+2  A: 

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

Pete Kirkham
It's GPL so I can't use it in our commercial program. Sorry for not being clear about that.
Michel de Ruiter
Writing wrapper class for enum (array of enums as indices and bits as values) are rather trivial, and for sure it is more safe (and elegant) than using raw enums.
macias