C ++ múltiplas enums em um argumento de função usando bit ou "|"
-
18-09-2019 - |
Pergunta
Recentemente, me deparei com algumas funções em que você pode passar várias enumes como esta:
myFunction(One | Two);
Já que acho que essa é uma maneira muito elegante, tentei implementar algo assim:
void myFunction(int _a){
switch(_a){
case One:
cout<<"!!!!"<<endl;
break;
case Two:
cout<<"?????"<<endl;
break;
}
}
Agora, se eu tentar chamar a função com um | Segundo, quero que os dois casos de switch sejam chamados. Não sou muito bom com operadores binários, então não sei realmente o que fazer. Quaisquer idéias seriam ótimas!
Obrigado!
Solução
Para isso, você tem que fazer enumes como:
enum STATE {
STATE_A = 1,
STATE_B = 2,
STATE_C = 4
};
O valor do elemento enum do IE deve estar no poder de 2 para selecionar um caso válido ou se a instrução.
Então, quando você gosta:
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);
}
Outras dicas
Os operadores bitwise se comportam bem apenas com os poderes de 2:
0010
| 0100
------
0110 // both bits are set
0110
& 0100
------
0100 // nonzero, i.e. true: the flag is set
Se você tentar fazer o mesmo com números arbitrários, obterá resultados inesperados:
0101 // 5
| 1100 // 12
------
1101 // 13
Que contém os números possíveis (arbitrários) como sinalizadores definidos: 0001
(1), 0100
(4), 0101
(5), 1000
(8), 1001
(9), 1100
(12), 1101
(13)
Então, em vez de dar duas opções, você apenas deu seis.
Normalmente, os argumentos combinados dessa maneira são sinalizadores (um valor com um único conjunto de bits) com um valor decimal de 1, 2, 4, 8, etc. Supondo que um e dois sigam essa regra, você não pode usar um interruptor para verificar Ambas. Os interruptores seguem apenas um caminho. Seu argumento combinado não é igual a um ou dois, mas uma combinação deles (1 | 2 == 3). Você pode verificar se um ou dois está definido como este:
if (_a & One)
{
}
if (_a & Two)
{
}
Lembre -se de que uma enumeração padrão sem valores explícitos contam apenas para cima, não usará o próximo bit. Se o seu próximo valor definido for três, provavelmente será igual a 3, o que não é um valor de um único bit e depois agirá como se você tivesse passado os dois sinalizadores (um | dois) para a função. Você precisará definir os valores da enumeração.
Você deve dividir os possíveis "tokens" (não sobrepostos, é claro ... Use Power of 2):
if (_a & One) { ... }
Não é elegante realmente fazer o que você deseja com 1 Switch Declarenting: Split usando if
declarações.
É melhor você fazer isso com um conjunto de declarações if ...
ou seja
if ( _a & ONE )
{
// Do stuff.
}
if ( _a & TWO )
{
// Do other stuff.
}
EDIT: Você também pode fazê -lo em uma declaração de troca, mas seria um pesadelo. Você precisaria de algo assim
switch( _a )
{
case ONE:
// Handle ONE.
break;
case TWO:
// Handle TWO.
break;
case ONE | TWO:
// Handle ONE.
// Handle TWO.
break;
};
É relativamente sensato por apenas duas opções, mas uma vez que você obtém mais do que isso começa a balançar fora de controle. Se você tiver 32 opções, teria uma instrução SWITCH que provavelmente se encaixaria em qualquer máquina. Tudo na solução "se" é muito mais limpo e muito mais sã :)