Ось варіант для біткових масок, якщо ви фактично не використовуєте окремі значення перерахунків (наприклад, вам не потрібно їх вимикати) ... і якщо ви не переживаєте за збереження бінарної сумісності, тобто: байдуже, де живуть твої шматочки ... якими ти, мабуть, є. Також вам краще не надто перейматися масштабуванням та контролем доступу. Гммм, енюми мають деякі приємні властивості для бітових полів ... цікаво, чи хтось коли-небудь це пробував :)
struct AnimalProperties
{
bool HasClaws : 1;
bool CanFly : 1;
bool EatsFish : 1;
bool Endangered : 1;
};
union AnimalDescription
{
AnimalProperties Properties;
int Flags;
};
void TestUnionFlags()
{
AnimalDescription propertiesA;
propertiesA.Properties.CanFly = true;
AnimalDescription propertiesB = propertiesA;
propertiesB.Properties.EatsFish = true;
if( propertiesA.Flags == propertiesB.Flags )
{
cout << "Life is terrible :(";
}
else
{
cout << "Life is great!";
}
AnimalDescription propertiesC = propertiesA;
if( propertiesA.Flags == propertiesC.Flags )
{
cout << "Life is great!";
}
else
{
cout << "Life is terrible :(";
}
}
Ми можемо бачити, що життя чудове, у нас є наші дискретні цінності, і ми маємо прихильність до & і | нашому серцю вміст, який все ще має контекст того, що означають його шматочки. Все послідовно і передбачувано ... для мене ... доки я продовжую використовувати компілятор VC ++ Microsoft w / Update 3 на Win10 x64 і не торкатися моїх прапорів компілятора :)
Незважаючи на те, що все чудово ... ми маємо певний контекст щодо значення прапорів зараз, оскільки його в об'єднанні з бітфілдом у жахливому реальному світі, де ваша програма може відповідати за більш ніж одне окреме завдання, яке ви могли б зробити як і раніше випадково (досить легко) разом розбийте два прапори різних союзів (скажімо, AnimalProperties та ObjectProperties, оскільки вони обидва ints), змішавши всі ваші біти, що є жахливою помилкою відстежити ... і як я знаю багато людей на цій посаді не працюють з растровими масками дуже часто, оскільки створити їх легко, а підтримувати їх важко.
class AnimalDefinition {
public:
static AnimalDefinition *GetAnimalDefinition( AnimalFlags flags ); //A little too obvious for my taste... NEXT!
static AnimalDefinition *GetAnimalDefinition( AnimalProperties properties ); //Oh I see how to use this! BORING, NEXT!
static AnimalDefinition *GetAnimalDefinition( int flags ); //hmm, wish I could see how to construct a valid "flags" int without CrossFingers+Ctrl+Shift+F("Animal*"). Maybe just hard-code 16 or something?
AnimalFlags animalFlags; //Well this is *way* too hard to break unintentionally, screw this!
int flags; //PERFECT! Nothing will ever go wrong here...
//wait, what values are used for this particular flags field? Is this AnimalFlags or ObjectFlags? Or is it RuntimePlatformFlags? Does it matter? Where's the documentation?
//Well luckily anyone in the code base and get confused and destroy the whole program! At least I don't need to static_cast anymore, phew!
private:
AnimalDescription m_description; //Oh I know what this is. All of the mystery and excitement of life has been stolen away :(
}
Тоді ви зробите свою декларацію об'єднання приватною, щоб запобігти прямому доступу до "Прапорів", і вам доведеться додати геттери / сетери та перевантаження операторів, потім зробити макрос для всього цього, і ви, як правило, повертаєтесь туди, де ви почали, коли намагалися зробіть це за допомогою Enum.
На жаль, якщо ви хочете, щоб ваш код був переносним, я не думаю, що існує спосіб A) гарантувати біт макет або B) визначити біт макет під час компіляції (так що ви можете відстежувати його і принаймні виправляти зміни в межах версії / платформи тощо)
Зміщення в структурі з бітовими полями
Під час виконання ви можете грати з трюками під час встановлення полів та XORing прапорів, щоб побачити, які біти змінилися, для мене звучить досить шалено, хоча вірші, які мають 100% послідовне, незалежне від платформи, і повністю детерміноване рішення, тобто: ENUM.
TL; DR: Не слухайте ненависників. C ++ - це не англійська. Тільки тому, що буквальне визначення скороченого ключового слова, успадкованого від C, може не відповідати вашому використанню, не означає, що ви не повинні використовувати його, коли визначення ключового слова C і C ++ абсолютно включає ваш випадок використання. Ви також можете використовувати структури для моделювання речей, окрім структур, а класи для речей, окрім шкільних та соціальних каст. Ви можете використовувати float для заземлених значень. Ви можете використовувати char для змінних, які не є ні спаленими, ні особами в романі, виставі чи фільмі. Будь-який програміст, який переходить до словника, щоб визначити значення ключового слова, перш ніж специфікація мови, буде ... ну я там тримаю свою мову.
Якщо ви хочете, щоб ваш код був змодельований на розмовній мові, вам найкраще буде писати в Objective-C, який, до речі, також сильно використовує перерахунки для бітфілів.
[Flags]
атрибут працює чудово, тобто:[Flags] enum class FlagBits{ Ready = 1, ReadMode = 2, WriteMode = 4, EOF = 8, Disabled = 16};