views:

386

answers:

6

Hi,

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!

+2  A: 

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
+1  A: 

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
thanks, you are right, I use if statements now and it works like a charm!
moka
+2  A: 

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
+4  A: 

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
Even better, use `enum STATE { STATE_A = 1 << 0, STATE_B = 1 << 1, STATE_C = 1 << 2 };` - I find that much more explicit.
DevSolar
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
thanks, I did it like you guys suggested and it works!
moka
+2  A: 

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.

Jurily
A: 

If the processes are simple, you may want to consider using boolean logic instead of if statements:

bool status(false);
status = (state & FLAG_1) && (/* data processing */);
status = (state & FLAG_2) && (/* data processing */);

This technique follows conditional instruction execution that some processors have (such as the ever popular ARM series). The C++ and C languages guarantee that if the first expression evaluates to false, the remaining expressions will not be evaluated.

The truth will be told in the assembly listing generated by the compiler.

Thomas Matthews