Come usare le enumerazioni come flag in C ++?

Trattare enum s come flag funziona bene in C # tramite l’attributo [Flags] , ma qual è il modo migliore per farlo in C ++?

Ad esempio, mi piacerebbe scrivere:

 enum AnimalFlags { HasClaws = 1, CanFly =2, EatsFish = 4, Endangered = 8 }; seahawk.flags = CanFly | EatsFish | Endangered; 

Tuttavia, ottengo errori del compilatore per quanto riguarda le conversioni int / enum . C’è un modo più bello per esprimere questo rispetto al semplice casting smussato? Preferibilmente, non voglio fare affidamento su costrutti da librerie di terze parti come boost o Qt.

EDIT: Come indicato nelle risposte, posso evitare l’errore del compilatore dichiarando seahawk.flags come int . Tuttavia, mi piacerebbe avere un meccanismo per rafforzare la sicurezza del tipo, quindi qualcuno non può scrivere seahawk.flags = HasMaximizeButton .

Il modo “corretto” è definire gli operatori di bit per l’enum, come:

 enum AnimalFlags { HasClaws = 1, CanFly =2, EatsFish = 4, Endangered = 8 }; inline AnimalFlags operator|(AnimalFlags a, AnimalFlags b) {return static_cast(static_cast(a) | static_cast(b));} 

Ecc. Resto degli operatori di bit. Modificare se necessario se l’intervallo enum supera l’intervallo int.

Nota (anche un po ‘fuori tema): un altro modo per rendere le bandiere univoche può essere fatto usando un bit shift. Io stesso, trovo questo più facile da leggere.

 enum Flags { A = 1 << 0, // binary 0001 B = 1 << 1, // binary 0010 C = 1 << 2, // binary 0100 D = 1 << 3, // binary 1000 }; 

Può contenere valori fino a un int, quindi è la maggior parte delle volte 32 flag che si riflette chiaramente nella quantità di spostamento.

Per le persone pigre come me, ecco la soluzione basata su modelli per copiare e incollare:

 template inline T operator~ (T a) { return (T)~(int)a; } template inline T operator| (T a, T b) { return (T)((int)a | (int)b); } template inline T operator& (T a, T b) { return (T)((int)a & (int)b); } template inline T operator^ (T a, T b) { return (T)((int)a ^ (int)b); } template inline T& operator|= (T& a, T b) { return (T&)((int&)a |= (int)b); } template inline T& operator&= (T& a, T b) { return (T&)((int&)a &= (int)b); } template inline T& operator^= (T& a, T b) { return (T&)((int&)a ^= (int)b); } 

Di che tipo è la variabile seahawk.flags?

Nel C ++ standard, le enumerazioni non sono sicure per tipo. Sono effettivamente interi.

AnimalFlags NON dovrebbe essere il tipo della tua variabile, la tua variabile dovrebbe essere int e l’errore andrà via.

Mettere valori esadecimali come altre persone suggerite non è necessario, non fa differenza.

I valori enum sono di tipo int per impostazione predefinita. Quindi puoi sicuramente OR bit per bit combinarli e metterli insieme e memorizzare il risultato in un int.

Il tipo enum è un sottoinsieme limitato di int il cui valore è uno dei valori enumerati. Quindi, quando si crea un nuovo valore al di fuori di tale intervallo, non è ansible assegnarlo senza eseguire il casting su una variabile del tipo enum.

Puoi anche modificare i tipi di valore enumerario se lo desideri, ma non c’è motivo per questa domanda.

EDIT: Il poster ha detto che erano interessati alla sicurezza del tipo e non vogliono un valore che non dovrebbe esistere all’interno del tipo int.

Ma sarebbe insicuro mettere un valore al di fuori della gamma di AnimalFlags all’interno di una variabile di tipo AnimalFlags.

Esiste un modo sicuro per verificare i valori fuori intervallo anche se all’interno del tipo int …

 int iFlags = HasClaws | CanFly; //InvalidAnimalFlagMaxValue-1 gives you a value of all the bits // smaller than itself set to 1 //This check makes sure that no other bits are set. assert(iFlags & ~(InvalidAnimalFlagMaxValue-1) == 0); enum AnimalFlags { HasClaws = 1, CanFly =2, EatsFish = 4, Endangered = 8, // put new enum values above here InvalidAnimalFlagMaxValue = 16 }; 

Quanto sopra non ti impedisce di mettere una bandiera non valida da un’altra enumerazione che ha il valore 1,2,4 o 8.

Se si desidera la sicurezza del tipo assoluto, è sufficiente creare uno std :: set e memorizzare ogni flag all’interno di esso. Non è efficiente in termini di spazio ma è sicuro per tipo e offre la stessa capacità di un bitflag int.

C ++ 0x note: enum fortemente tipizzati

In C ++ 0x puoi finalmente digitare valori di enum sicuri ….

 enum class AnimalFlags { CanFly = 2, HasClaws = 4 }; if(CanFly == 2) { }//Compiling error 

Nota se stai lavorando in ambiente Windows, c’è una macro DEFINE_ENUM_FLAG_OPERATORS definita in winnt.h che fa il lavoro per te. Quindi in questo caso, puoi farlo:

 enum AnimalFlags { HasClaws = 1, CanFly =2, EatsFish = 4, Endangered = 8 }; DEFINE_ENUM_FLAG_OPERATORS(AnimalFlags) seahawk.flags = CanFly | EatsFish | Endangered; 

Trovo che la risposta attualmente accettata da eidolon sia troppo pericolosa. L’ottimizzatore del compilatore potrebbe fare ipotesi su possibili valori nell’enumerazione e potresti recuperare i dati inutili con valori non validi. E di solito nessuno vuole definire tutte le permutazioni possibili in enumerazioni di bandiere.

Come dice Brian R. Bondy di seguito, se stai usando C ++ 11 (che tutti dovrebbero, è così bello) ora puoi farlo più facilmente con la enum class :

 enum class ObjectType : uint32_t { ANIMAL = (1 << 0), VEGETABLE = (1 << 1), MINERAL = (1 << 2) }; constexpr enum ObjectType operator |( const enum ObjectType selfValue, const enum ObjectType inValue ) { return (enum ObjectType)(uint32_t(selfValue) | uint32_t(inValue)); } // ... add more operators here. 

Ciò garantisce una dimensione e un intervallo di valori stabili specificando un tipo per l'enumerazione, inibendo il downcast automatico dell'enumerazione a ints, ecc. Usando la enum class , e usa constexpr per garantire che il codice per gli operatori sia in linea e quindi altrettanto veloce dei numeri normali .

Per persone bloccate con dialetti C ++ pre-11

Se fossi stato bloccato con un compilatore che non supportava C ++ 11, andrei con il wrapping di un int-type in una class che quindi consente solo l'uso di operatori bit a bit e i tipi da quell'enumerazione per impostare i suoi valori:

 template::type> class SafeEnum { public: SafeEnum() : mFlags(0) {} SafeEnum( ENUM singleFlag ) : mFlags(singleFlag) {} SafeEnum( const SafeEnum& original ) : mFlags(original.mFlags) {} SafeEnum& operator |=( ENUM addValue ) { mFlags |= addValue; return *this; } SafeEnum operator |( ENUM addValue ) { SafeEnum result(*this); result |= addValue; return result; } SafeEnum& operator &=( ENUM maskValue ) { mFlags &= maskValue; return *this; } SafeEnum operator &( ENUM maskValue ) { SafeEnum result(*this); result &= maskValue; return result; } SafeEnum operator ~() { SafeEnum result(*this); result.mFlags = ~result.mFlags; return result; } explicit operator bool() { return mFlags != 0; } protected: UNDERLYING mFlags; }; 

Puoi definirlo praticamente come un normale enum + typedef:

 enum TFlags_ { EFlagsNone = 0, EFlagOne = (1 << 0), EFlagTwo = (1 << 1), EFlagThree = (1 << 2), EFlagFour = (1 << 3) }; typedef SafeEnum TFlags; 

Anche l'utilizzo è simile:

 TFlags myFlags; myFlags |= EFlagTwo; myFlags |= EFlagThree; if( myFlags & EFlagTwo ) std::cout << "flag 2 is set" << std::endl; if( (myFlags & EFlagFour) == EFlagsNone ) std::cout << "flag 4 is not set" << std::endl; 

Ed è anche ansible sovrascrivere il tipo sottostante per enumerazioni binarie stabili (come enum foo : type C ++ 11 enum foo : type ) usando il secondo parametro template, ovvero typedef SafeEnum TFlags; .

Ho contrassegnato l' operator bool override con la parola chiave explicit di C ++ 11 per impedirgli di generare conversioni int, dato che questi potrebbero causare il blocco dell'insieme di flag in 0 o 1 al momento della scrittura. Se non è ansible utilizzare C ++ 11, lasciare il sovraccarico e riscrivere il primo condizionale nell'esempio di utilizzo come (myFlags & EFlagTwo) == EFlagTwo .

Il modo più semplice per farlo è quello mostrato qui , usando il set di classi standard della libreria.

Per emulare la caratteristica C # in un modo sicuro dal tipo, dovresti scrivere un wrapper di template attorno al bitset, sostituendo gli argomenti int con un enum dato come parametro di tipo al template. Qualcosa di simile a:

  template  class FlagSet { bitset bits; FlagSet(T enumVal) { bits.set(enumVal); } // etc. }; enum MyFlags { FLAG_ONE, FLAG_TWO }; FlagSet myFlag; 

Secondo me nessuna delle risposte finora è l’ideale. Per essere ideale mi aspetterei la soluzione:

  1. Supporta il == != , = , & , &= , | , |= e ~ operatori nel senso convenzionale (cioè a & b )
  2. Essere sicuro di tipo, ovvero non consentire l’assegnazione di valori non enumerati come letterali o di tipi interi (ad eccezione di combinazioni bit a bit di valori enumerati) o consentire l’assegnazione di una variabile enum a un tipo intero
  3. Permetti espressioni come if (a & b)...
  4. Non richiede macro malvagie, funzionalità specifiche di implementazione o altri hack

La maggior parte delle soluzioni finora cadono sui punti 2 o 3. Il secondo di WebDancer è a mio avviso ma fallisce al punto 3 e deve essere ripetuto per ogni enum.

La mia soluzione proposta è una versione generalizzata di WebDancer che si rivolge anche al punto 3:

 #include  #include  template::value, T>::type> class auto_bool { T val_; public: constexpr auto_bool(T val) : val_(val) {} constexpr operator T() const { return val_; } constexpr explicit operator bool() const { return static_cast>(val_) != 0; } }; template ::value, T>::type> constexpr auto_bool operator&(T lhs, T rhs) { return static_cast( static_cast::type>(lhs) & static_cast::type>(rhs)); } template ::value, T>::type> constexpr T operator|(T lhs, T rhs) { return static_cast( static_cast::type>(lhs) | static_cast::type>(rhs)); } enum class AnimalFlags : uint8_t { HasClaws = 1, CanFly = 2, EatsFish = 4, Endangered = 8 }; enum class PlantFlags : uint8_t { HasLeaves = 1, HasFlowers = 2, HasFruit = 4, HasThorns = 8 }; int main() { AnimalFlags seahawk = AnimalFlags::CanFly; // Compiles, as expected AnimalFlags lion = AnimalFlags::HasClaws; // Compiles, as expected PlantFlags rose = PlantFlags::HasFlowers; // Compiles, as expected // rose = 1; // Won't compile, as expected if (seahawk != lion) {} // Compiles, as expected // if (seahawk == rose) {} // Won't compile, as expected // seahawk = PlantFlags::HasThorns; // Won't compile, as expected seahawk = seahawk | AnimalFlags::EatsFish; // Compiles, as expected lion = AnimalFlags::HasClaws | // Compiles, as expected AnimalFlags::Endangered; // int eagle = AnimalFlags::CanFly | // Won't compile, as expected // AnimalFlags::HasClaws; // int has_claws = seahawk & AnimalFlags::CanFly; // Won't compile, as expected if (seahawk & AnimalFlags::CanFly) {} // Compiles, as expected seahawk = seahawk & AnimalFlags::CanFly; // Compiles, as expected return 0; } 

Questo crea sovraccarichi degli operatori necessari ma utilizza SFINAE per limitarli a tipi enumerati. Si noti che nell’interesse della brevità non ho definito tutti gli operatori, ma l’unico che è diverso è il & . Gli operatori sono attualmente globali (vale a dire si applicano a tutti i tipi enumerati) ma ciò potrebbe essere ridotto posizionando i sovraccarichi in uno spazio dei nomi (cosa faccio), o aggiungendo ulteriori condizioni di SFINAE (magari usando particolari tipi sottostanti, o alias di tipo appositamente creati ). Il underlying_type_t è una funzionalità di C ++ 14 ma sembra essere ben supportato ed è facile da emulare per C ++ 11 con un semplice template using underlying_type_t = underlying_type::type;

Se il tuo compilatore non supporta ancora enum fortemente tipizzati, puoi dare un’occhiata al seguente articolo dal sorgente c ++:

Dall’astratto:

Questo articolo presenta una soluzione al problema di vincolare le operazioni bit a
consentire solo quelli sicuri e legittimi e trasformare tutte le manipolazioni bit non valide in errori in fase di compilazione. Meglio di tutti, la syntax delle operazioni di bit rimane invariata e il codice che lavora con i bit non ha bisogno di essere modificato, tranne forse per correggere errori che non erano ancora stati rilevati.

Mi sono trovato a fare la stessa domanda e ho trovato una soluzione generica basata su C ++ 11, simile a quella di soru:

 template  class FlagSet { private: using TUNDER = typename std::underlying_type::type; std::bitset::max()> m_flags; public: FlagSet() = default; template  FlagSet(TENUM f, ARGS... args) : FlagSet(args...) { set(f); } FlagSet& set(TENUM f) { m_flags.set(static_cast(f)); return *this; } bool test(TENUM f) { return m_flags.test(static_cast(f)); } FlagSet& operator|=(TENUM f) { return set(f); } }; 

L’interfaccia può essere migliorata per il gusto. Quindi può essere utilizzato in questo modo:

 FlagSet flags{Flags::FLAG_A, Flags::FLAG_C}; flags |= Flags::FLAG_D; 

Lo standard C ++ parla esplicitamente di questo, vedere la sezione “17.5.2.1.3 Tipi di maschera di bit”:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf

Dato questo “modello” ottieni:

 enum AnimalFlags : unsigned int { HasClaws = 1, CanFly = 2, EatsFish = 4, Endangered = 8 }; constexpr AnimalFlags operator|(AnimalFlags X, AnimalFlags Y) { return static_cast( static_cast(X) | static_cast(Y)); } AnimalFlags& operator|=(AnimalFlags& X, AnimalFlags Y) { X = X | Y; return X; } 

E simile per gli altri operatori. Nota anche il “constexpr”, è necessario se vuoi che il compilatore sia in grado di eseguire il tempo di compilazione degli operatori.

Se si utilizza C ++ / CLI e si desidera assegnare in modo efficace i membri enum delle classi ref, è necessario utilizzare invece i riferimenti di tracciamento:

 AnimalFlags% operator|=(AnimalFlags% X, AnimalFlags Y) { X = X | Y; return X; } 

NOTA: questo esempio non è completo, vedere la sezione “17.5.2.1.3 Tipi di maschera di bit” per un set completo di operatori.

Stai confondendo oggetti e collezioni di oggetti. In particolare, si confondono i flag binari con set di flag binari. Una soluzione adeguata sarebbe simile a questa:

 // These are individual flags enum AnimalFlag // Flag, not Flags { HasClaws = 0, CanFly, EatsFish, Endangered }; class AnimalFlagSet { int m_Flags; public: AnimalFlagSet() : m_Flags(0) { } void Set( AnimalFlag flag ) { m_Flags |= (1 << flag); } void Clear( AnimalFlag flag ) { m_Flags &= ~ (1 << flag); } bool Get( AnimalFlag flag ) const { return (m_Flags >> flag) & 1; } }; 

Ecco un’opzione per le maschere di bit se non si ha effettivamente un uso per i singoli valori enum (ad esempio non è necessario distriggersrli) … e se non si è preoccupati di mantenere la compatibilità binaria, ovvero: non importa dove vivono i tuoi pezzi … quale probabilmente sei. Inoltre, è meglio non preoccuparsi troppo dell’ambito e del controllo degli accessi. Hmmm, le enumerazioni hanno delle buone proprietà per i campi di bit … chiedo se qualcuno l’abbia mai provato 🙂

 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 :("; } } 

Possiamo vedere che la vita è grande, abbiamo i nostri valori discreti e abbiamo una buona int per & e | | al nostro contenuto del cuore, che ha ancora il contesto di ciò che i suoi bit significano. Tutto è coerente e prevedibile ... per me ... purché continui a utilizzare il compilatore VC ++ di Microsoft con l'aggiornamento 3 su Win10 x64 e non tocchi i miei flag del compilatore 🙂

Anche se tutto è grandioso ... abbiamo un po 'di contesto sul significato delle bandiere ora, dato che è in un sindacato con il bitfield nel terribile mondo reale in cui il tuo programma potrebbe essere responsabile di più di un singolo compito discreto che potresti ancora accidentalmente (abbastanza facilmente) distruggere due campi di flag di diversi sindacati insieme (ad esempio, AnimalProperties e ObjectProperties, dal momento che sono entrambi gli interi), mescolando tutti i tuoi bit, che è un bug orribile da rintracciare ... e come so molte persone su questo post non lavorano molto spesso con le maschere di bit, dal momento che la loro creazione è semplice e il loro mantenimento è 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 :( } 

Quindi rendi privata la dichiarazione del tuo sindacato per impedire l'accesso diretto a "Flags", e devi aggiungere getter / setter e overload dell'operatore, quindi creare una macro per tutto questo e in fondo sei praticamente indietro dove hai iniziato quando hai provato a fallo con un Enum.

Sfortunatamente se vuoi che il tuo codice sia portatile, non credo che ci sia alcun modo per A) garantire il layout dei bit o B) determinare il layout dei bit in fase di compilazione (in modo che tu possa tenerne traccia e almeno correggere le modifiche attraverso versioni / piattaforms ecc.) Offset in una struttura con campi di bit

In fase di esecuzione puoi giocare trucchi w / settando i campi e XORando i flag per vedere quali bit sono cambiati, mi sembra piuttosto schifoso anche se i versi hanno una soluzione al 100% coerente, indipendente dalla piattaforma e completamente deterministica, ad esempio: un ENUM.

TL; DR: Non ascoltare gli odiatori. Il C ++ non è inglese. Solo perché la definizione letterale di una parola chiave abbreviata ereditata da C potrebbe non corrispondere al tuo utilizzo non significa che non dovresti usarla quando la definizione di parola chiave C e C ++ include assolutamente il tuo caso d'uso. Puoi anche usare le strutture per modellare cose diverse dalle strutture e classi per cose diverse dalla scuola e dalla casta sociale. Puoi usare float per i valori che sono messi a terra. Puoi usare char per variabili che non sono né bruciate né una persona in un romanzo, in un gioco o in un film. Qualsiasi programmatore che va al dizionario per determinare il significato di una parola chiave prima della specifica della lingua è un ... beh, terrò la mia lingua lì.

Se vuoi che il tuo codice sia modellato sulla lingua parlata, ti conviene scrivere in Objective-C, che tra l'altro usa pesantemente enum per i bitfield.

Mi piacerebbe approfondire la risposta di Uliwitness , correggendo il suo codice per C ++ 98 e usando l’ idioma di Safe Bool , per mancanza del modello std::underlying_type<> e della parola chiave explicit nelle versioni C ++ sotto C ++ 11.

L’ho anche modificato in modo che i valori enum possano essere sequenziali senza alcun incarico esplicito, quindi puoi averli

 enum AnimalFlags_ { HasClaws, CanFly, EatsFish, Endangered }; typedef FlagsEnum AnimalFlags; seahawk.flags = AnimalFlags() | CanFly | EatsFish | Endangered; 

È quindi ansible ottenere il valore di flag non elaborati con

 seahawk.flags.value(); 

Ecco il codice.

 template  class FlagsEnum { typedef Underlying FlagsEnum::* RestrictedBool; public: FlagsEnum() : m_flags(Underlying()) {} FlagsEnum(EnumType singleFlag): m_flags(1 << singleFlag) {} FlagsEnum(const FlagsEnum& original): m_flags(original.m_flags) {} FlagsEnum& operator |=(const FlagsEnum& f) { m_flags |= f.m_flags; return *this; } FlagsEnum& operator &=(const FlagsEnum& f) { m_flags &= f.m_flags; return *this; } friend FlagsEnum operator |(const FlagsEnum& f1, const FlagsEnum& f2) { return FlagsEnum(f1) |= f2; } friend FlagsEnum operator &(const FlagsEnum& f1, const FlagsEnum& f2) { return FlagsEnum(f1) &= f2; } FlagsEnum operator ~() const { FlagsEnum result(*this); result.m_flags = ~result.m_flags; return result; } operator RestrictedBool() const { return m_flags ? &FlagsEnum::m_flags : 0; } Underlying value() const { return m_flags; } protected: Underlying m_flags; }; 

Come sopra (Kai) o fai quanto segue. In realtà le enumerazioni sono “Enumerazioni”, quello che vuoi fare è avere un set, quindi dovresti davvero usare stl :: set

 enum AnimalFlags { HasClaws = 1, CanFly =2, EatsFish = 4, Endangered = 8 }; int main(void) { AnimalFlags seahawk; //seahawk= CanFly | EatsFish | Endangered; seahawk= static_cast(CanFly | EatsFish | Endangered); } 

Ecco la mia soluzione senza bisogno di sovraccaricare o castare:

 namespace EFoobar { enum { FB_A = 0x1, FB_B = 0x2, FB_C = 0x4, }; typedef long Flags; } void Foobar(EFoobar::Flags flags) { if (flags & EFoobar::FB_A) // do sth ; if (flags & EFoobar::FB_B) // do sth ; } void ExampleUsage() { Foobar(EFoobar::FB_A | EFoobar::FB_B); EFoobar::Flags otherflags = 0; otherflags|= EFoobar::FB_B; otherflags&= ~EFoobar::FB_B; Foobar(otherflags); } 

Penso che sia ok, perché identifichiamo enum e int inte (non fortemente tipizzati).

Proprio come una (più lunga) nota a margine, se tu

  • voglio usare enumerazioni fortemente tipizzate e
  • non hai bisogno di pesanti trucchi con le tue bandiere
  • le prestazioni non sono un problema

Vorrei venire con questo:

 #include  enum class EFoobarFlags { FB_A = 1, FB_B, FB_C, }; void Foobar(const std::set& flags) { if (flags.find(EFoobarFlags::FB_A) != flags.end()) // do sth ; if (flags.find(EFoobarFlags::FB_B) != flags.end()) // do sth ; } void ExampleUsage() { Foobar({EFoobarFlags::FB_A, EFoobarFlags::FB_B}); std::set otherflags{}; otherflags.insert(EFoobarFlags::FB_B); otherflags.erase(EFoobarFlags::FB_B); Foobar(otherflags); } 

usando gli elenchi di inizializzatori C ++ 11 e la enum class .

Forse come NS_OPTIONS di Objective-C.

 #define ENUM(T1, T2) \ enum class T1 : T2; \ inline T1 operator~ (T1 a) { return (T1)~(int)a; } \ inline T1 operator| (T1 a, T1 b) { return static_cast((static_cast(a) | static_cast(b))); } \ inline T1 operator& (T1 a, T1 b) { return static_cast((static_cast(a) & static_cast(b))); } \ inline T1 operator^ (T1 a, T1 b) { return static_cast((static_cast(a) ^ static_cast(b))); } \ inline T1& operator|= (T1& a, T1 b) { return reinterpret_cast((reinterpret_cast(a) |= static_cast(b))); } \ inline T1& operator&= (T1& a, T1 b) { return reinterpret_cast((reinterpret_cast(a) &= static_cast(b))); } \ inline T1& operator^= (T1& a, T1 b) { return reinterpret_cast((reinterpret_cast(a) ^= static_cast(b))); } \ enum class T1 : T2 ENUM(Options, short) { FIRST = 1 << 0, SECOND = 1 << 1, THIRD = 1 << 2, FOURTH = 1 << 3 }; auto options = Options::FIRST | Options::SECOND; options |= Options::THIRD; if ((options & Options::SECOND) == Options::SECOND) cout << "Contains second option." << endl; if ((options & Options::THIRD) == Options::THIRD) cout << "Contains third option." << endl; return 0; // Output: // Contains second option. // Contains third option. 

Only syntactic sugar. No additional metadata.

 namespace UserRole // grupy { constexpr uint8_t dea = 1; constexpr uint8_t red = 2; constexpr uint8_t stu = 4; constexpr uint8_t kie = 8; constexpr uint8_t adm = 16; constexpr uint8_t mas = 32; } 

Flag operators on integral type just works.