116 Stimmen

Namespaces für Aufzählungstypen - bewährte Verfahren

Oft benötigt man mehrere Aufzählungstypen zusammen. Manchmal kommt es zu einem Namenskonflikt. Hierfür gibt es zwei Lösungen: die Verwendung eines Namensraums oder die Verwendung "größerer" Aufzählungselementnamen. Für die Namespace-Lösung gibt es zwei mögliche Implementierungen: eine Dummy-Klasse mit verschachteltem Enum oder ein vollwertiger Namespace.

Ich bin auf der Suche nach den Vor- und Nachteilen aller drei Ansätze.

// oft seen hand-crafted name clash solution
enum eColors { cRed, cColorBlue, cGreen, cYellow, cColorsEnd };
enum eFeelings { cAngry, cFeelingBlue, cHappy, cFeelingsEnd };
void setPenColor( const eColors c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cColorBlue: //...
        //...
    }
 }

// (ab)using a class as a namespace
class Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
class Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
void setPenColor( const Colors::e c ) {
    switch (c) {
        default: assert(false);
        break; case Colors::cRed: //...
        break; case Colors::cBlue: //...
        //...
    }
 }

 // a real namespace?
 namespace Colors { enum e { cRed, cBlue, cGreen, cYellow, cEnd }; };
 namespace Feelings { enum e { cAngry, cBlue, cHappy, cEnd }; };
 void setPenColor( const Colors::e c ) {
    switch (c) {
        default: assert(false);
        break; case Colors::cRed: //...
        break; case Colors::cBlue: //...
        //...
    }
  }

19 Stimmen

Zunächst einmal würde ich Farbe::Rot, Gefühl:Wütend, etc. verwenden.

0 Stimmen

Gute Frage, ich habe den Namensraum method.... verwendet ;)

19 Stimmen

Die Vorsilbe "c" für alles beeinträchtigt die Lesbarkeit.

87voto

Drew Dormann Punkte 54591

Original C++03 Antwort:

Le site profitieren de un namespace (über eine class ) ist, dass Sie Folgendes verwenden können using Deklarationen, wenn Sie wollen.

Le site problème mit der Verwendung eines namespace ist, dass Namespaces an anderer Stelle im Code erweitert werden können. In einem großen Projekt kann man nicht sicher sein, dass zwei verschiedene Enums nicht beide denken, sie hießen eFeelings

Für einfacher aussehenden Code verwende ich eine struct da Sie vermutlich wollen, dass der Inhalt öffentlich ist.

Wenn Sie eine dieser Praktiken anwenden, sind Sie der Zeit voraus und brauchen dies wahrscheinlich nicht weiter zu hinterfragen.

Neuere, C++11 Ratschläge:

Wenn Sie C++11 oder höher verwenden, enum class werden die Enum-Werte implizit in den Enum-Namen einbezogen.

Mit enum class verlieren Sie implizite Konvertierungen und Vergleiche mit Integer-Typen, aber in der Praxis kann Ihnen das helfen, zweideutigen oder fehlerhaften Code zu entdecken.

4 Stimmen

Ich stimme mit der Struktur-Idee überein. Und danke für das Kompliment:)

3 Stimmen

+1 Ich konnte mich nicht an die C++11 "enum class" Syntax erinnern. Ohne diese Funktion sind Enums unvollständig.

0 Stimmen

Gibt es eine Möglichkeit, "using" für den impliziten Geltungsbereich der "enum class" zu verwenden. z.B. wird das Hinzufügen von "using Color::e;" zum Code die Verwendung von "cRed" erlauben und wissen, dass dies Color::e::cRed sein sollte?

22voto

jmihalicza Punkte 1998

FYI In C++0x gibt es eine neue Syntax für Fälle wie das, was Sie erwähnt (siehe C++0x-Wiki-Seite )

enum class eColors { ... };
enum class eFeelings { ... };

14voto

Mark Lakata Punkte 18998

Ich habe die vorangegangenen Antworten zu etwas Ähnlichem zusammengefasst: (EDIT: Dies ist nur für Pre-C++11 nützlich. Wenn Sie C++11 verwenden, verwenden Sie enum class )

Ich habe eine große Header-Datei, die alle meine Projekt-Enums enthält, weil diese Enums von den Worker-Klassen gemeinsam genutzt werden und es nicht sinnvoll ist, die Enums in die Worker-Klassen selbst zu integrieren.

Le site struct vermeidet die Öffentlichkeit: syntaktischer Zucker und die typedef können Sie Variablen dieser Enums in anderen Workerklassen deklarieren.

Ich glaube nicht, dass die Verwendung eines Namensraums etwas bringt. Vielleicht liegt das daran, dass ich ein C#-Programmierer bin, und da kann man haben den Namen des Aufzählungstyps zu verwenden, wenn auf die Werte verwiesen wird, also bin ich daran gewöhnt.

    struct KeySource {
        typedef enum { 
            None, 
            Efuse, 
            Bbram
        } Type;
    };

    struct Checksum {
        typedef enum {
            None =0,
            MD5 = 1,
            SHA1 = 2,
            SHA2 = 3
        } Type;
    };

    struct Encryption {
        typedef enum {
            Undetermined,
            None,
            AES
        } Type;
    };

    struct File {
        typedef enum {
            Unknown = 0,
            MCS,
            MEM,
            BIN,
            HEX
        } Type;
    };

...

class Worker {
    File::Type fileType;
    void DoIt() {
       switch(fileType) {
       case File::MCS: ... ;
       case File::MEM: ... ;
       case File::HEX: ... ;
    }
}

10voto

Charles Anderson Punkte 17827

Ich würde auf jeden Fall vermeiden, eine Klasse dafür zu verwenden; verwenden Sie stattdessen einen Namespace. Die Frage läuft darauf hinaus, ob ein Namespace oder eindeutige IDs für die Enum-Werte verwendet werden sollen. Ich persönlich würde einen Namespace verwenden, damit meine ids kürzer und hoffentlich selbsterklärender sind. Dann könnte der Anwendungscode eine "using namespace"-Direktive verwenden und alles besser lesbar machen.

Aus Ihrem obigen Beispiel:

using namespace Colors;

void setPenColor( const e c ) {
    switch (c) {
        default: assert(false);
        break; case cRed: //...
        break; case cBlue: //...
        //...
    }
}

0 Stimmen

Könnten Sie einen Hinweis geben auf por qué Sie würden einen Namespace einer Klasse vorziehen?

0 Stimmen

@xtofl : man kann nicht 'using class Colors` schreiben

2 Stimmen

@MSalters: Sie können auch nicht schreiben Colors someColor = Red; da der Namensraum keinen Typ darstellt. Sie müssten also schreiben Colors::e someColor = Red; statt, was ziemlich kontraintuitiv ist.

8voto

Michał Górny Punkte 17618

Der Vorteil der Verwendung einer Klasse ist, dass Sie eine vollwertige Klasse darauf aufbauen können.

#include <cassert>

class Color
{
public:
    typedef enum
    {
        Red,
        Blue,
        Green,
        Yellow
    } enum_type;

private:
    enum_type _val;

public:
    Color(enum_type val = Blue)
        : _val(val)
    {
        assert(val <= Yellow);
    }

    operator enum_type() const
    {
        return _val;
    }
};

void SetPenColor(const Color c)
{
    switch (c)
    {
        case Color::Red:
            // ...
            break;
    }
}

Wie das obige Beispiel zeigt, können Sie eine Klasse verwenden:

  1. verbieten (leider nicht zur Kompilierzeit), dass C++ einen Cast von einem ungültigen Wert erlaubt,
  2. einen Standardwert (ungleich Null) für neu erstellte Enums festlegen,
  3. weitere Methoden hinzufügen, z. B. für die Rückgabe einer String-Repräsentation einer Auswahl.

Beachten Sie nur, dass Sie Folgendes angeben müssen operator enum_type() damit C++ weiß, wie es Ihre Klasse in ein zugrunde liegendes Enum umwandeln kann. Andernfalls können Sie den Typ nicht an eine switch Erklärung.

1 Stimmen

Steht diese Lösung in irgendeinem Zusammenhang mit dem, was hier gezeigt wird? de.wikibooks.org/wiki/More_C%2B%2B_Idioms/Type_Safe_Enum Ich denke darüber nach, wie ich es zu einer Vorlage machen kann, damit ich das Muster nicht jedes Mal neu schreiben muss, wenn ich es brauche.

0 Stimmen

@SasQ: Es scheint ähnlich zu sein, ja. Das ist wahrscheinlich die gleiche Idee. Allerdings bin ich nicht sicher, ob eine Vorlage vorteilhaft ist, es sei denn, Sie fügen eine Menge von "gemeinsamen" Methoden in dort.

0 Stimmen

1. Das stimmt nicht ganz. Sie können die Kompilierzeit überprüfen lassen, dass die Enum gültig ist, über const_expr oder über den privaten Konstruktor für einen int.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X