Несколько перечислений в C++ в одном аргументе функции с использованием поразрядного ввода или «|»

StackOverflow https://stackoverflow.com/questions/1874051

Вопрос

Недавно я наткнулся на некоторые функции, в которых можно передавать несколько перечислений, например:

myFunction(One | Two);

Поскольку я считаю, что это действительно элегантный способ, я сам попытался реализовать что-то подобное:

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

Теперь, если я попытаюсь вызвать функцию с одним | Во -вторых, я хочу, чтобы оба дела переключались.Я не очень хорошо разбираюсь в двоичных операторах, поэтому не знаю, что делать.Любые идеи были бы великолепны!

Спасибо!

Это было полезно?

Решение

Для этого вам нужно сделать перечисления типа:

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

то естьЗначение элемента перечисления должно быть в степени 2, чтобы выбрать допустимый регистр или оператор if.

Итак, когда вам нравится:

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

Другие советы

Побитовые операторы хорошо себя ведут только со степенью 2:

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


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

Если вы попытаетесь сделать то же самое с произвольными числами, вы получите неожиданные результаты:

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

Который содержит возможные (произвольные) числа в качестве установленных флагов: 0001 (1), 0100 (4), 0101 (5), 1000 (8), 1001 (9), 1100 (12), 1101 (13)

То есть вместо двух вариантов вы дали шесть.

Обычно аргументы, объединенные таким образом, представляют собой флаги (значения с одним установленным битом) с десятичным значением 1, 2, 4, 8 и т. д.Предполагая, что One и Two следуют этому правилу, вы не можете использовать переключатель для проверки обоих.Коммутаторы следуют только по одному пути.Ваш объединенный аргумент равен не одному или двум, а их комбинации (1 | 2 == 3).Вы можете проверить, установлено ли значение «Один» или «Два», следующим образом:

if (_a & One)
{

}
if (_a & Two)
{

}

Помните, что стандартное перечисление без явных значений будет просто считать вверх, а не использовать следующий бит.Если ваше следующее определенное значение — «Три», оно, скорее всего, будет равно 3, что не является значением одного бита, и тогда оно будет действовать так, как если бы вы передали в функцию оба флага (Один | Два).Вам нужно будет установить значения перечисления самостоятельно.

Вы должны разделить возможные «токены» (конечно, не перекрывающиеся...используйте степень 2):

if (_a & One) { ... }

Не элегантно, на самом деле делайте то, что хотите, с помощью одного оператора переключения:разделить с помощью if заявления.

Лучше сделать это с помощью набора операторов if...

т.е.

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

редактировать:Вы также можете сделать это в операторе переключателя, но это будет кошмар.Вам понадобится что-то вроде этого

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

case TWO:
   // Handle TWO.
   break;

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

Это относительно разумно только для двух вариантов, но как только вы получите больше, он начнет выходить из-под контроля.Если у вас есть 32 варианта, у вас будет оператор переключения, который вряд ли поместится на какой-либо машине.Все в решении «если» намного чище и гораздо разумнее :)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top