Я почти всегда заканчиваю тем, что использовал MIT или BSD (они эквивалентны), начиная с него
, Что, и набор GNU/GPL обычно экстремисты, когда Вы встречаетесь с ними в дикой природе.
Вы можете определить перечисление, определяющее «однобитовые» значения (обратите внимание, что включающая структура действует здесь только как контекст именования, так что вы можете написать, например, MyFlags :: EVEN
):
struct MyFlags{
enum Value{
EVEN = 0x01,
ODD = 0x02,
ANOTHER_FLAG = 0x04,
YET_ANOTHER_FLAG = 0x08,
SOMETHING_ELSE = 0x10,
SOMETHING_COMPLETELY_DIFFERENT = 0x20
};
};
, а затем используйте его так:
int CreateNum(MyFlags::Value flags){
if (flags & MyFlags::EVEN){
// do something...
}
}
void main(){
CreateNum((MyFlags::Value)(MyFlags::EVEN | MyFlags::ODD));
}
или просто так:
int CreateNum(int flags){
if (flags & MyFlags::EVEN){
// do something...
}
}
void main(){
CreateNum(MyFlags::EVEN | MyFlags::ODD);
}
Вы также можете просто объявить целочисленные константы, но, на мой взгляд, перечисление более четкое.
Примечание: Я обновил сообщение, чтобы учесть некоторые комментарии, спасибо!
Я поддержал ответ orsogufo, но мне всегда нравилось делать следующее для определения значений:
enum Value{
EVEN = (1<<0),
ODD = (1<<2),
ANOTHER_FLAG = (1<<3),
YET_ANOTHER_FLAG = (1<<4),
SOMETHING_ELSE = (1<<5),
SOMETHING_COMPLETELY_DIFFERENT = (1<<6),
ANOTHER_EVEN = EVEN|ANOTHER_FLAG
};
<< - оператор сдвига. Увеличение правой части позволяет вам генерировать последовательные битовые маски, перемещая 1 по одному биту за раз. Это те же значения для простых флагов, но для меня легче читается и становится очевидным, если вы пропустите или дублируете значение.
Мне также нравится комбинировать некоторые общие комбинации флагов, когда это необходимо.
Вы ошиблись в тестах. Вам нужно что-то вроде (flags & EVEN)
, где EVEN - это целое число с одним набором битов (1, 2, 4, 8, 16 - некоторая степень двойки). (Целое число может быть int или enum. У вас может быть макрос, но это, как правило, не очень хорошая идея.)
Вы можете использовать указанную вами нотацию, перегрузив flags :: operator == (flagvalue е)
, но это плохая идея.
enum flags {
EVEN = 0x0100,
ODD = 0x0200,
BELOW_TEN = 0x0400,
ABOVETEN = 0x0800,
HUNDRED = 0x1000,
MASK = 0xff00
};
void some_func(int id_and_flags)
{
int the_id = id_and_flags & ~MASK;
int flags = id_and_flags & MASK;
if ((flags & EVEN) && (the_id % 2) == 1)
++the_id;
if ((flags & ODD) && (the_id % 2) == 0)
++the_id;
// etc
}
Также иллюстрирует маскирование битовых полей, которое может быть полезно, когда вам просто нужно добавить упрощенную дополнительную функциональность без добавления какой-либо дополнительной структуры данных.
Вы можете использовать const int
следующим образом:
const int FLAG1 = 0x0001;
const int FLAG2 = 0x0010;
const int FLAG3 = 0x0100;
// ...
И когда вы его используете:
int CreateNum(int flags)
{
if( flags & FLAG1 )
// FLAG1 is present
if( flags & FLAG2 )
// FLAG2 is present
// ...
}
Конечно, вы можете установить один или несколько флагов в свои флаги, используя |
оператор.
Используйте степень двойки как отдельные константы , например
enum Flags { EVEN = 0x1, ODD = 0x2, GREATER_TEN = 0x4 };
, и вы используете логический оператор и "&" для тестирования, например
if( flags & GREATER_THAN_TEN)
num = 11;
if( (flags & EVEN) && (num % 2) == 1 )
num++;
else if ( (flags & ODD) && (num % 2) == 0 )
num++;
return num;