Использование бинарных флагов для представления состояний, параметров и т. Д. - PullRequest
1 голос
/ 10 сентября 2009

Если бы я хотел представить состояния или параметры или что-то подобное, используя двоичные «флаги», чтобы я мог передать их и сохранить их в объекте типа OPTION1 | OPTION2, где OPTION1 равно 0001 и OPTION2 равно 0010, так передается значение 0011, представляющее собой набор опций.

Как бы я сделал это в C ++? Я думал что-то вроде

enum Option {
    Option_1 = 0x01,
    Option_2 = 0x02,
    Option_3 = 0x04,
    //...
}

void doSomething(Option options) {
    //...
}

int main() {
    doSomething(Option_1|Option_2);
}

Но в идеале doSomething знает, как интерпретировать данную опцию.

Я на правильном пути? Есть ли способ лучше?

Обновление

И разве мне не придется определять Option для каждой возможной комбинации, также?

Ответы [ 4 ]

6 голосов
/ 10 сентября 2009

Это обычный способ, которым все это делается. doSomething может использовать побитовый оператор and, чтобы увидеть, выбрана ли опция:

if (options & Option_1){ 
  // option 1 is selected
}

В качестве альтернативы, вы можете рассмотреть возможность использования битовых полей :

struct Options {
    unsigned char Option_1 : 1;
    unsigned char Option_2 : 1;
};

Options o;
o.Option_1 = 1;
o.Option_2 = 0;
4 голосов
/ 10 сентября 2009

Я бы так и сделал.Однако есть много приемов, которые вы можете использовать, чтобы сделать перечисление более читабельным:

enum Option {
    Option1 = 1 /*<< 0*/,
    Option2 = 1 << 1,
    Option3 = 1 << 2,
    // etc.
};

Более того, вам нужно будет указать побитовые операторы для вашего перечисления.Рассмотрим что-то вроде ASL enum_ops утилит, чтобы помочь с этим.

3 голосов
/ 10 сентября 2009

Стоит отметить, что люди обычно используют такие флаги, чтобы определить функцию следующим образом:

void doSomething( unsigned int options ) 
{
    //...
}

все остальное будет работать именно так, как вы хотите:)

Другой способ - создать свой собственный класс "Флаги". Тогда у вас есть пара функций в классе:

bool GetOption( Option option )
{
    return (m_Option & option) > 0;
}

void SetOption( Option option )
{
    m_Option |= option;
}

void ClearOption( Option option )
{
    m_Option &= ~option;
}

или даже перегружать операторов, чтобы сделать именно так, как вы хотите, например:

Flags( unsigned int options ) :
   m_Option( options )
{
}

Flags operator|( const Flags& flags )
{
    return Flags( m_Option | flags.m_Option );
}

и т. Д.

1 голос
/ 11 сентября 2009

Вы можете попробовать stl bitset . Некоторые люди будут проповедовать, что вы всегда должны использовать их вместо битовых флагов в стиле C. Тем не менее, оба решения прекрасно IMO.

...