2009-12-09 8 views
6

Recentemente ho sono imbattuto in alcune funzioni in cui è possibile passare più enumerazioni come questo:C++ enumerazioni multiple in un argomento di funzione utilizzando bit per bit o "|"

myFunction(One | Two); 

Poiché penso che questo sia un modo davvero elegante ho cercato di implementare qualcosa di simile me:

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

ora se provo a chiamare la funzione con One | Due, voglio che entrambi i casi vengano chiamati. Non sono molto bravo con gli operatori binari quindi non so davvero cosa fare. Qualunque idea sarebbe apprezzata!

Grazie!

+1

Pubblica la tua definizione di 'enum' .. ti sei ricordato di renderli tutti i poteri di 2? – eduffy

+1

Nota il nome _a è riservato all'implementazione C++, a meno che non sia il nome di un membro della classe. –

risposta

11

Per questo si deve fare enumerazioni come:

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

cioè enum valore dell'elemento deve essere in potenza di 2 per selezionare caso valido o if.

Così, quando ti piace:

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); 
} 
+8

Ancora meglio, usa 'enum STATE {STATE_A = 1 << 0, STATE_B = 1 << 1, STATE_C = 1 << 2};' - Lo trovo molto più esplicito. – DevSolar

+3

Non sarebbero stati tra l'altro. Gli stati sono pensati per essere esclusivi. È più probabile che siano bandiere (in cui le singole bandiere sono indipendenti l'una dall'altra). – paxdiablo

+0

grazie, l'ho fatto come hai suggerito voi ragazzi e funziona! – moka

2

È necessario dividere i possibili "gettoni" (divieto di cumulo delle naturalmente ... usare il potere di 2):

if (_a & One) { ... } 

Non elegante davvero fare quello che vuoi con la dichiarazione 1 interruttore: split con if dichiarazioni .

2

Si sta meglio farlo con una serie di istruzioni if ​​...

cioè

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

edit: Si potrebbe anche farlo in un'istruzione switch ma sarebbe un incubo. Youd bisogno di qualcosa come questo

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

case TWO: 
    // Handle TWO. 
    break; 

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

sua relativamente sano di mente per solo 2 opzioni, ma una volta che si ottiene più di che inizia a palloncino fuori controllo. Se disponi di 32 opzioni, avresti un'istruzione switch che difficilmente si adatta a qualsiasi macchina. Tutto nella soluzione "se" è molto più pulito e molto più sano :)

+0

grazie, hai ragione, io uso se le dichiarazioni ora e funziona come un incantesimo! – moka

3

Di solito gli argomenti combinati in questo modo sono flag (un valore con un singolo bit impostato) con un valore decimale di 1, 2, 4, 8 , Supponendo che One e Two seguano questa regola, non è possibile utilizzare un interruttore per verificare entrambi. Gli switch seguono solo un percorso. Il tuo argomento combinato non è uguale a Uno o Due, ma una combinazione di essi (1 | 2 == 3). È possibile controllare per vedere se uno o due è impostato in questo modo:

if (_a & One) 
{ 

} 
if (_a & Two) 
{ 

} 

ricordare che un enum standard senza valori espliciti sarà solo contare verso l'alto, non usare il bit successivo. Se il tuo prossimo valore definito è Tre, sarà probabilmente uguale a 3, che non è un valore di un singolo bit, e agirà come se avessi passato entrambi i flag (Uno | Due) alla funzione. Dovrai impostare tu stesso i valori dell'enum.

8

operatori bit a bit si comportano bene solo con potenze di 2:

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


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

Se si tenta di fare lo stesso con i numeri arbitrari, si otterrà inaspettato risultati:

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

Che contiene i numeri (arbitrari) possibili come contrassegni impostati: 0001 (1), 0100 (4), 0101 (5), 1000 (8), 1001 (9), 1100 (12), 1101 (13)

Così, invece di dare due opzioni, è appena dato sei.