Come usare la class enum C ++ 11 per le bandiere

Dì che ho una tale class:

enum class Flags : char { FLAG_1 = 1; FLAG_2 = 2; FLAG_3 = 4; FLAG_4 = 8; }; 

Ora posso avere una variabile con flag di tipo e assegnare un valore 7 ad esempio? Posso farlo:

 Flags f = Flags::FLAG_1 | Flags::FLAG_2 | Flags::FLAG_3; 

o

 Flags f = 7; 

Questa domanda sorge perché nell’enum non ho definito il valore per 7 .

Devi scrivere il tuo operator| sovraccarico operator| (e presumibilmente operator& via).

 Flags operator|(Flags lhs, Flags rhs) { return static_cast(static_cast(lhs) | static_cast(rhs)); } 

La conversione di un numero intero in un tipo di enumerazione (con scope o meno) è ben definita purché il valore sia compreso nell’intervallo dei valori di enumerazione (e UB altrimenti; [expr.static.cast] / p10). Per le enumerazioni con tipi di base fissi (che include tutte le enumerazioni con scope; [dcl.enum] / p5), l’intervallo di valori di enumerazione è uguale all’intervallo di valori del tipo sottostante ([dcl.enum] / p8). Le regole sono più complicate se il tipo sottostante non è fisso, quindi non farlo 🙂

Per favore, non farlo. Se hai bisogno di farlo, probabilmente le enum class non sono ciò che ti serve.

@TC ti ha mostrato come farlo, purché tu specifichi il tipo sottostante, ma ti imbatterai in luoghi in cui il tuo programma fa cose che proprio non dovrebbe.

Un esempio è dove si usa un switch e si ha un case per ogni valore enum definito .

per esempio

 enum class my_enum: unsigned int{ first = 1, second = 2, third = 4, fourth = 8 }; int main(){ auto e = static_cast(static_cast(my_enum::first) | static_cast(my_enum::second)); switch(e){ case my_enum::first: case my_enum::second: case my_enum::third: case my_enum::fourth: return 0; } std::cout << "Oh, no! You reached a part of the program you weren't meant to!\n"; return 1; } 

Produrrà:

 Oh, no! You reached a part of the program you weren't meant to! 

quindi restituire il codice di errore 1 .

Questo è anche un esempio del perché dovresti sempre avere un caso default , ovviamente, ma non è questo il mio punto.

Naturalmente, si potrebbe obiettare che fintanto che l'utente della enum class non usi mai direttamente il valore se non passando a una funzione; sarebbe un buon modo per limitare i valori di un bitset. Ma sono sempre stato un po 'troppo affidabile e trovo std::uint[n]_t e alcune variabili di constexpr nel modo migliore (se un utente imposta un bit non valido non fa semplicemente nulla).

Quello che stai facendo non è proprio adatto per la enum class , perché sconfigge lo scopo di avere un'enumerazione dell'ambito. Non è più ansible enumerare i valori se lo si imposta su uno non definito.

Il codice in questione non viene compilato. Ma puoi fare qualcosa del genere,

 enum class Flags : char { FLAG_1 = 1, FLAG_2 = 2, FLAG_3 = 4, FLAG_4 = 8, }; int main() { Flags f = static_cast(7); Flags f1 = static_cast( static_cast(Flags::FLAG_1) | static_cast(Flags::FLAG_2) | static_cast(Flags::FLAG_3) ); return 0; } 

e funziona

A questo punto, probabilmente ha senso definire la tua class per gestirlo.

  /** Warning: Untested code **/ struct Flag { static Flag Flag_1; static Flag Flag_2; static Flag Flag_3; static Flag Flag_4; Flag operator = (Flag); private: char const value; }; Flag operator | (Flag, Flag);