Aquí hay una opción para las máscaras de bits si en realidad no utiliza los valores de enumeración individuales (por ejemplo, no necesita desactivarlos) ... y si no le preocupa mantener la compatibilidad binaria, es decir: usted no me importa dónde viven tus partes ... lo que probablemente estés. Además, es mejor que no te preocupes demasiado por el alcance y el control de acceso. Hmmm, las enumeraciones tienen algunas buenas propiedades para los campos de bits ... me pregunto si alguien ha intentado eso :)
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 :(";
}
}
Podemos ver que la vida es genial, tenemos nuestros valores discretos, y tenemos un buen int para & y | al contenido de nuestro corazón, que todavía tiene contexto de lo que significan sus partes Todo es consistente y predecible ... para mí ... siempre y cuando siga usando el compilador VC ++ de Microsoft con la Actualización 3 en Win10 x64 y no toque las banderas de mi compilador :)
A pesar de que todo es genial ... tenemos un contexto en cuanto al significado de las banderas ahora, ya que está en una unión con el campo de bits en el terrible mundo real donde su programa puede ser responsable de más de una tarea discreta que podría todavía accidentalmente (con bastante facilidad) rompen dos campos de banderas de diferentes uniones (por ejemplo, AnimalProperties y ObjectProperties, ya que ambos son ints), mezclando todos sus bits, que es un error horrible para rastrear ... y cómo sé Muchas personas en esta publicación no trabajan con máscaras de bits muy a menudo, ya que construirlas es fácil y mantenerlas es difícil.
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 :(
}
Entonces, hace que la declaración de su sindicato sea privada para evitar el acceso directo a "Banderas", y tiene que agregar captadores / establecedores y sobrecargas del operador, luego crea una macro para todo eso, y está básicamente de vuelta a donde comenzó cuando intentó haz esto con una Enum.
Desafortunadamente, si desea que su código sea portátil, no creo que haya alguna forma de A) garantizar el diseño de bits o B) determinar el diseño de bits en el momento de la compilación (para que pueda rastrearlo y al menos corregir los cambios) versiones / plataformas, etc.)
Offset en una estructura con campos de bits
En el tiempo de ejecución, puedes jugar trucos con los campos y XORingar las banderas para ver qué bits cambiaron, me suena bastante horrible, aunque los versos tienen una solución 100% consistente, independiente de la plataforma y completamente determinista, es decir: un ENUM.
TL; DR: No escuches a los que odian. C ++ no es inglés. El hecho de que la definición literal de una palabra clave abreviada heredada de C no se ajuste a su uso no significa que no deba usarla cuando la definición de C y C ++ de la palabra clave incluya absolutamente su caso de uso. También puede usar estructuras para modelar cosas que no sean estructuras y clases para cosas que no sean la escuela y la casta social. Puede usar flotante para valores que están conectados a tierra. Puede usar char para variables que no están sin grabar ni una persona en una novela, obra de teatro o película. Cualquier programador que vaya al diccionario para determinar el significado de una palabra clave antes de la especificación del idioma es un ... bueno, callaré allí.
Si desea que su código siga el modelo del lenguaje hablado, lo mejor sería escribir en Objective-C, que, por cierto, también utiliza enumeraciones en gran medida para los campos de bits.
[Flags]
atributo funciona bien, es decir:[Flags] enum class FlagBits{ Ready = 1, ReadMode = 2, WriteMode = 4, EOF = 8, Disabled = 16};