Voici une option pour les masques de bits si vous n'avez pas réellement d'utilisation des valeurs d'énumération individuelles (par exemple, vous n'avez pas besoin de les désactiver) ... et si vous n'êtes pas préoccupé par le maintien de la compatibilité binaire, c'est-à-dire: vous peu importe où vivent vos morceaux ... ce que vous êtes probablement. De plus, vous feriez mieux de ne pas vous préoccuper trop de la portée et du contrôle d'accès. Hmmm, les enums ont de belles propriétés pour les champs de bits ... je me demande si quelqu'un a déjà essayé ça :)
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 :(";
}
}
Nous pouvons voir que la vie est belle, nous avons nos valeurs discrètes, et nous avons un bel intérêt pour & et | à notre coeur content, qui a toujours le contexte de ce que signifient ses morceaux. Tout est cohérent et prévisible ... pour moi ... tant que je continue à utiliser le compilateur VC ++ de Microsoft avec la mise à jour 3 sur Win10 x64 et que je ne touche pas les drapeaux de mon compilateur :)
Même si tout va bien ... nous avons maintenant un certain contexte quant à la signification des drapeaux, car c'est dans une union avec le champ de bits dans le terrible monde réel où votre programme peut être responsable de plus d'une seule tâche discrète que vous pourriez écrasez toujours accidentellement (assez facilement) deux champs de drapeaux de différents syndicats ensemble (par exemple, AnimalProperties et ObjectProperties, car ils sont tous les deux intimes), mélangeant tous vos bits, ce qui est un horrible bug à retracer ... et comment je sais beaucoup de personnes sur ce post ne travaillent pas très souvent avec des masques bitmap, car leur construction est facile et leur maintenance est difficile.
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 :(
}
Donc, vous rendez votre déclaration d'union privée pour empêcher l'accès direct à "Flags", et devez ajouter des getters / setters et des surcharges d'opérateurs, puis créer une macro pour tout cela, et vous êtes fondamentalement de retour là où vous avez commencé lorsque vous avez essayé de faites cela avec un Enum.
Malheureusement, si vous voulez que votre code soit portable, je ne pense pas qu'il y ait moyen de A) garantir la disposition des bits ou B) déterminer la disposition des bits au moment de la compilation (afin que vous puissiez le suivre et au moins corriger les changements à travers versions / plates-formes, etc.)
Offset dans une structure avec des champs de bits
Au moment de l'exécution, vous pouvez jouer des tours en définissant les champs et en XORing les indicateurs pour voir quels bits ont changé, cela me semble assez merdique si les versets ont une solution 100% cohérente, indépendante de la plate-forme et complètement déterministe, c'est-à-dire: un ENUM.
TL; DR: N'écoutez pas les haineux. C ++ n'est pas l'anglais. Ce n'est pas parce que la définition littérale d'un mot-clé abrégé hérité de C peut ne pas correspondre à votre utilisation que vous ne devriez pas l'utiliser lorsque le C et définition C ++ du mot clé inclut absolument votre cas d'utilisation. Vous pouvez également utiliser des structures pour modéliser des choses autres que des structures et des classes pour des choses autres que l'école et la caste sociale. Vous pouvez utiliser float pour les valeurs mises à la terre. Vous pouvez utiliser char pour les variables qui ne sont ni non brûlées ni une personne dans un roman, une pièce de théâtre ou un film. Tout programmeur qui va au dictionnaire pour déterminer la signification d'un mot-clé avant la spécification de la langue est un ... eh bien, je vais garder ma langue là-bas.
Si vous voulez que votre code soit modelé sur le langage parlé, vous feriez mieux d'écrire en Objective-C, qui utilise également fortement les énumérations pour les champs de bits.
[Flags]
attribut fonctionne très bien, c'est-à-dire:[Flags] enum class FlagBits{ Ready = 1, ReadMode = 2, WriteMode = 4, EOF = 8, Disabled = 16};