Un enum X : int
(C #) o enum class X : int
(C ++ 11) è un tipo che ha un campo interno nascosto di int
che può contenere qualsiasi valore. Inoltre, un numero di costanti predefinite di X
sono definite sull'enumerazione. È possibile lanciare l'enum al suo valore intero e viceversa. Questo è tutto vero sia in C # che in C ++ 11.
Le enumerazioni in C # non solo vengono utilizzate per contenere singoli valori, ma anche per contenere combinazioni bitwise di flag, come per Raccomandazione di Microsoft . Tali enumerazioni sono (di solito, ma non necessariamente) decorate con l'attributo [Flags]
. Per semplificare la vita degli sviluppatori, gli operatori bit a bit (OR, AND, ecc.) Sono sovraccaricati in modo che tu possa facilmente fare qualcosa di simile a questo (C #):
void M(NumericType flags);
M(NumericType.Sign | NumericType.ZeroPadding);
Sono uno sviluppatore C # esperto, ma ho programmato C ++ solo per un paio di giorni e non sono noto con le convenzioni C ++. Intendo utilizzare un enum di C ++ 11 esattamente nello stesso modo in cui ero abituato a fare in C #. In C ++ 11 gli operatori bit a bit su enumerati non sono sovraccaricati, quindi volevo sovraccaricarli .
Questo ha sollecitato un dibattito e le opinioni sembrano variare tra tre opzioni:
-
Una variabile del tipo enum viene utilizzata per contenere il campo di bit, simile a C #:
void M(NumericType flags); // With operator overloading: M(NumericType::Sign | NumericType::ZeroPadding); // Without operator overloading: M(static_cast<NumericType>(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding)));
Ma ciò contrasterebbe la filosofia enum strongmente tipizzata delle enunciati scope di C ++ 11.
-
Utilizza un numero intero semplice se desideri memorizzare una combinazione di enumerazioni bit a bit:
void M(int flags); M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
Ma questo ridurrebbe tutto ad un
int
, lasciandoti senza indizio su quale tipo dovresti inserire nel metodo. -
Scrivi una classe separata che sovraccaricherà gli operatori e manterrà i flag bit a bit in un campo intero nascosto:
class NumericTypeFlags { unsigned flags_; public: NumericTypeFlags () : flags_(0) {} NumericTypeFlags (NumericType t) : flags_(static_cast<unsigned>(t)) {} //...define BITWISE test/set operations }; void M(NumericTypeFlags flags); M(NumericType::Sign | NumericType::ZeroPadding);
( codice completo di user315052 )
Ma in questo caso non hai IntelliSense o qualsiasi altro supporto che ti indichi i possibili valori.
So che questa è una domanda soggettiva , ma: Cosa approccio dovrei usare? Quale approccio, se esiste, è il più ampiamente riconosciuto in C ++? Quale approccio utilizzi quando gestisci i campi di bit e perché ?
Naturalmente dal momento che tutti e tre gli approcci funzionano, sono alla ricerca di ragioni tecniche e di fatto, convenzioni generalmente accettate e non semplicemente preferenze personali.
Ad esempio, a causa del mio background C # tendo ad andare con l'approccio 1 in C ++. Questo ha l'ulteriore vantaggio che il mio ambiente di sviluppo può suggerire i possibili valori, e con gli operatori enum sovraccarichi questo è facile da scrivere e capire, e abbastanza pulito. E la firma del metodo mostra chiaramente quale tipo di valore si aspetta. Ma la maggior parte delle persone qui non sono d'accordo con me, probabilmente per una buona ragione.