Вот вариант для битовых масок, если вы на самом деле не используете отдельные значения перечисления (например, вам не нужно их отключать) ... и если вы не беспокоитесь о поддержке бинарной совместимости то есть: вам все равно, где ваши биты живут ... что вы, вероятно,. Кроме того, вы не должны быть слишком обеспокоены областью видимости и контролем доступа. Хммм, перечисления имеют некоторые хорошие свойства для битовых полей ... интересно, кто-нибудь когда-либо пробовал это:)
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 :(";
}
}
Мы можем видеть, что жизнь прекрасна, у нас есть свои дискретные ценности, и у нас есть хороший int для & и | к нашему сердцу содержание, которое все еще имеет контекст того, что означают его биты. Все непротиворечиво и предсказуемо ... для меня ... пока я продолжаю использовать компилятор Microsoft VC ++ с обновлением 3 на Win10 x64 и не трогаю флаги моего компилятора:)
Несмотря на то, что все замечательно ... у нас есть некоторый контекст относительно значения флагов, поскольку он находится в единстве с битовым полем в ужасном реальном мире, где может быть ответственна ваша программа для более чем одной отдельной задачи вы все равно можете случайно (довольно легко) разбить два поля флагов различных объединений (скажем, AnimalProperties и ObjectProperties, так как они оба целые), смешивая все ваши биты, что является ужасной ошибкой для проследить ... и, насколько я знаю, многие люди в этом посте не очень часто работают с битовыми масками, поскольку создавать их легко, а поддерживать их сложно.
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) определить битовую компоновку во время компиляции (чтобы вы могли отслеживать и, по крайней мере, исправлять) для изменений между версиями / платформами и т. д.)
Смещение в структуре с битовыми полями
Во время выполнения вы можете разыгрывать трюки с установкой полей и установкой флагов XOR, чтобы увидеть, какие биты изменились, для меня это звучит довольно глупо, хотя стихи имеют 100% согласованное, независимое от платформы и полностью детерминированное решение, например: ENUM .
TL; DR:
Не слушай ненавистников. C ++ не английский. Тот факт, что буквальное определение сокращенного ключевого слова, унаследованного от C, может не подходить для вашего использования, не означает, что вы не должны использовать его, когда определение ключевого слова C и C ++ абсолютно включает ваш сценарий использования. Вы также можете использовать структуры, чтобы моделировать вещи, отличные от структур, и классы для вещей, отличных от школьной и социальной касты. Вы можете использовать float для значений, которые обоснованы. Вы можете использовать char для переменных, которые не являются ни сожженными, ни людьми в романе, пьесе или фильме. Любой программист, который идет в словарь, чтобы определить значение ключевого слова до того, как спецификация языка ... ну, я буду там держать язык за зубами.
Если вы хотите, чтобы ваш код был смоделирован на разговорном языке, вам лучше было бы писать в Objective-C, который, между прочим, также активно использует перечисления для битовых полей.