Ein enum X : int
(C #) oder enum class X : int
(C ++ 11) ist ein Typ, dessen verstecktes inneres Feld int
einen beliebigen Wert enthalten kann. Außerdem sind eine Reihe vordefinierter Konstanten von X
in der Enumeration definiert. Es ist möglich, die Enumeration auf ihren ganzzahligen Wert zu setzen und umgekehrt. Dies gilt sowohl für C # als auch für C ++ 11.
In C # werden Aufzählungen nicht nur zum Speichern einzelner Werte verwendet, sondern auch zum Speichern bitweiser Kombinationen von Flags, wie von Microsoft empfohlen . Solche Aufzählungen sind (normalerweise, aber nicht unbedingt) mit dem [Flags]
Attribut versehen. Um das Leben der Entwickler zu vereinfachen, sind die bitweisen Operatoren (OR, AND, etc ...) überladen, sodass Sie auf einfache Weise Folgendes tun können (C #):
void M(NumericType flags);
M(NumericType.Sign | NumericType.ZeroPadding);
Ich bin ein erfahrener C # -Entwickler, programmiere aber erst seit ein paar Tagen C ++ und bin mit den C ++ - Konventionen nicht vertraut. Ich beabsichtige, eine C ++ 11-Enumeration genauso zu verwenden, wie ich es in C # getan habe. In C ++ 11 sind die bitweisen Operatoren für bereichsspezifische Enums nicht überladen, daher wollte ich sie überladen .
Dies löste eine Debatte aus, und die Meinungen scheinen zwischen drei Optionen zu variieren:
Eine Variable vom Typ enum wird verwendet, um das Bitfeld zu halten, ähnlich wie in 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)));
Dies würde jedoch der stark typisierten Enum-Philosophie von C ++ 11 widersprechen.
Verwenden Sie eine einfache Ganzzahl, wenn Sie eine bitweise Kombination von Enums speichern möchten:
void M(int flags); M(static_cast<int>(NumericType::Sign) | static_cast<int>(NumericType::ZeroPadding));
Dies würde jedoch alles auf eine reduzieren
int
, sodass Sie keine Ahnung haben, welchen Typ Sie in die Methode einfügen sollen.Schreiben Sie eine separate Klasse, die Operatoren überlädt und die bitweisen Flags in einem versteckten Ganzzahlfeld enthält:
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);
( vollständiger Code von user315052 )
Dann haben Sie jedoch weder IntelliSense noch eine andere Unterstützung, um auf die möglichen Werte hinzuweisen.
Ich weiß, dass dies eine subjektive Frage ist , aber: Welchen Ansatz soll ich verwenden? Welcher Ansatz ist in C ++ am weitesten verbreitet? Welchen Ansatz verwenden Sie beim Umgang mit Bitfeldern und warum ?
Da alle drei Ansätze funktionieren, suche ich natürlich nach sachlichen und technischen Gründen, allgemein anerkannten Konventionen und nicht nur nach persönlichen Vorlieben.
Aufgrund meines C # -Hintergrunds tendiere ich beispielsweise dazu, Ansatz 1 in C ++ zu wählen. Dies hat den zusätzlichen Vorteil, dass meine Entwicklungsumgebung mich auf die möglichen Werte hinweisen kann, und bei überladenen Enum-Operatoren ist dies einfach zu schreiben und zu verstehen und ziemlich sauber. Und die Methodensignatur zeigt deutlich, welchen Wert sie erwartet. Aber die meisten Leute hier stimmen mir nicht zu, wahrscheinlich aus gutem Grund.
enum E { A = 1, B = 2, C = 4, };
, der Bereich ist 0..7
(3 Bit). Somit garantiert der C ++ - Standard explizit, dass # 1 immer eine praktikable Option ist. [Standardmäßig wird enum class
, enum class : int
sofern nicht anders angegeben, immer ein fester zugrunde liegender Typ verwendet.])