10

I recently came across some functions where you can pass multiple enums like this:

myFunction(One | Two);

Since I think this is a really elegant way I tried to implement something like that myself:

void myFunction(int _a){
    switch(_a){
        case One:
            cout<<"!!!!"<<endl;
            break;
        case Two:
            cout<<"?????"<<endl;
            break;
    }
}

now if I try to call the function with One | Two, I want that both switch cases get called. I am not really good with binary operators so I dont really know what to do. Any ideas would be great!

Thanks!

moka
  • 365
  • 1
  • 5
  • 10
  • 1
    Post your `enum` definition .. did you remember to make them all powers of 2? – eduffy Dec 09 '09 at 13:56
  • 1
    Note the name _a is reserved for the C++ implementation, unless it is the name of a class member. –  Dec 09 '09 at 14:16

5 Answers5

17

For that you have to make enums like :

enum STATE {
  STATE_A = 1,
  STATE_B = 2,
  STATE_C = 4
};

i.e. enum element value should be in power of 2 to select valid case or if statement.

So when you do like:

void foo( int state) {

  if ( state & STATE_A ) {
    //  do something 
  }

  if ( state & STATE_B ) {
    //  do something 
  }

  if ( state & STATE_C ) {
    //  do something 
  }   
}

int main() {
  foo( STATE_A | STATE_B | STATE_C);
}
Ashish
  • 8,441
  • 12
  • 55
  • 92
  • 12
    Even better, use `enum STATE { STATE_A = 1 << 0, STATE_B = 1 << 1, STATE_C = 1 << 2 };` - I find that much more explicit. – DevSolar Dec 09 '09 at 14:06
  • 3
    They wouldn't be states by the way. States are meant to be exclusive. They're more likely to be flags (where the individual flags are independent of each other). – paxdiablo Dec 09 '09 at 14:13
9

Bitwise operators behave well only with powers of 2:

  0010
| 0100
------
  0110  // both bits are set


  0110
& 0100
------
  0100  // nonzero, i.e. true: the flag is set

If you try to do the same with arbitrary numbers, you'll get unexpected results:

  0101  // 5
| 1100  // 12
------
  1101  // 13

Which contains the possible (arbitrary) numbers as set flags: 0001 (1), 0100 (4), 0101 (5), 1000 (8), 1001 (9), 1100 (12), 1101 (13)

So instead of giving two options, you just gave six.

György Andrasek
  • 8,187
  • 4
  • 48
  • 76
3

Usually arguments that are combined that way are flags (a value with a single bit set) with a decimal value of 1, 2, 4, 8, etc. Assuming that One and Two follow this rule, you cannot use a switch to check for both. Switches only follow one path. Your combined argument does not equal One or Two, but a combination of them (1 | 2 == 3). You can check to see if One or Two is set like this:

if (_a & One)
{

}
if (_a & Two)
{

}

Remember that a standard enum without explicit values will just count upwards, not use the next bit. If your next defined value is Three, it will likely equal 3 which is not a value of a single bit, and will then act as if you had passed both flags (One | Two) to the function. You'll need to set the values of the enum yourself.

Jimbo
  • 320
  • 3
  • 14
2

You must split the possible "tokens" (non-overlapping of course... use power of 2):

if (_a & One) { ... }

Not elegant really do what you want with 1 switch statement: split using if statements.

jldupont
  • 93,734
  • 56
  • 203
  • 318
2

You are better off doing it with a set of if statements ...

ie

if ( _a & ONE )
{
   // Do stuff.
}
if ( _a & TWO )
{
  // Do other stuff.
}

edit: You could also do it in a switch statement but it would be a nightmare. Youd need something like this

switch( _a )
{
case ONE:
   // Handle ONE.
   break;

case TWO:
   // Handle TWO.
   break;

case ONE | TWO:
   // Handle ONE.
   // Handle TWO.
   break;
};

Its relatively sane for only 2 options but once you get more than that it starts to balloon out of control. If you have 32-options you'd have a switch statement that would be unlikely to fit on any machine. All in the "if" solution is much cleaner and far more sane :)

Goz
  • 61,365
  • 24
  • 124
  • 204