Wie kann ich über eine Aufzählung iterieren?

Lesezeit: 2 Minuten

Wie kann ich uber eine Aufzahlung iterieren
Adam

Mir ist gerade aufgefallen, dass Sie keine mathematischen Standardoperatoren für eine Aufzählung wie ++ oder += verwenden können

Was ist also der beste Weg, um alle Werte in einer C++-Aufzählung zu durchlaufen?

  • Einer von vielen Ansätzen: Wenn Aufzählung einfach nicht genug ist: Aufzählungsklassen für C++. Und wenn Sie etwas Gekapselteres wollen, versuchen Sie es dieser Ansatz von James Kanze.

    – Don Wakefield

    4. November 2008 um 16:22 Uhr


  • Verknüpfte Elemente haben einige interessante Antworten.

    – Toni

    13. Juni 2013 um 1:27 Uhr

  • Diese Antworten scheinen das Problem nicht abzudecken int vielleicht nicht groß genug! ([C++03: 7.2/5])

    – Leichtigkeitsrennen im Orbit

    21. Juni 2013 um 10:03 Uhr

  • Interessanterweise können Sie definieren operator++ auf Aufzählungen; Sie können dies jedoch tun for(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++). Beachten Sie, dass Sie werfen müssen 0 zu Enum_E weil C++ Zuweisungsoperatoren für Aufzählungen verbietet.

    – weberc2

    25. Juni 2014 um 22:52 Uhr

  • Wenn es einen Kompilierzeitoperator gäbe, ähnlich wie sizeof, der ein std::initializer_list-Literal ausgeben könnte, das aus den Werten der Aufzählung besteht, hätten wir eine Lösung und keinen Laufzeit-Overhead.

    – jbruni

    13. Dezember 2017 um 23:56 Uhr

Wie kann ich uber eine Aufzahlung iterieren
andreas buykx

Der typische Weg ist wie folgt:

enum Foo {
  One,
  Two,
  Three,
  Last
};

for ( int fooInt = One; fooInt != Last; fooInt++ )
{
   Foo foo = static_cast<Foo>(fooInt);
   // ...
}

Bitte beachten Sie, die enum Last soll von der Iteration übersprungen werden. Mit dieser “Fälschung” Last enum müssen Sie Ihre Beendigungsbedingung in der for-Schleife nicht jedes Mal auf die letzte “echte” Aufzählung aktualisieren, wenn Sie eine neue Aufzählung hinzufügen möchten. Wenn Sie später weitere Aufzählungen hinzufügen möchten, fügen Sie sie einfach vor Last hinzu. Die Schleife in diesem Beispiel funktioniert immer noch.

Dies bricht natürlich zusammen, wenn die Enum-Werte angegeben werden:

enum Foo {
  One = 1,
  Two = 9,
  Three = 4,
  Last
};

Dies zeigt, dass eine Aufzählung nicht wirklich zum Durchlaufen gedacht ist. Die typische Art, mit einer Aufzählung umzugehen, besteht darin, sie in einer switch-Anweisung zu verwenden.

switch ( foo )
{
    case One:
        // ..
        break;
    case Two:  // intentional fall-through
    case Three:
        // ..
        break;
    case Four:
        // ..
        break;
     default:
        assert( ! "Invalid Foo enum value" );
        break;
}

Wenn Sie wirklich aufzählen möchten, füllen Sie die Aufzählungswerte in einen Vektor und iterieren Sie darüber. Dadurch werden auch die angegebenen Enum-Werte ordnungsgemäß behandelt.

  • Beachten Sie, dass Sie im ersten Teil des Beispiels, wenn Sie „i“ als Foo-Aufzählung und nicht als Int verwenden möchten, eine statische Umwandlung wie folgt durchführen müssen: static_cast(i)

    – Clayton

    17. März 2009 um 22:30 Uhr

  • Außerdem überspringen Sie Last in the loop. Sollte <= Last sein

    – Toni

    13. Juni 2013 um 1:24 Uhr

  • @Tony Last soll übersprungen werden. Wenn Sie später weitere Aufzählungen hinzufügen möchten, fügen Sie sie vor Last hinzu … die Schleife im ersten Beispiel funktioniert immer noch. Durch die Verwendung einer „gefälschten“ letzten Aufzählung müssen Sie Ihre Beendigungsbedingung in der for-Schleife nicht jedes Mal auf die letzte „echte“ Aufzählung aktualisieren, wenn Sie eine neue Aufzählung hinzufügen möchten.

    – timidpueo

    3. August 2013 um 21:06 Uhr

  • Beachten Sie, dass man einen Wert definieren sollte, damit diese Enum-Definition für Updates sicher ist UNKNOWN = 0. Außerdem würde ich vorschlagen, das einfach wegzulassen default Fall beim Umschalten von Enum-Werten, da es Fälle verbergen könnte, in denen die Behandlung von Werten bis zur Laufzeit vergessen wurde. Stattdessen sollte man alle Werte fest codieren und die verwenden UNKNOWN Feld, um Inkompatibilitäten zu erkennen.

    – Benjamin Bannier

    13. April 2017 um 15:08 Uhr

  • @timidpueo Deshalb nenne ich lieber den letzten Eintrag Count. Macht es etwas deutlicher.

    – Cerno

    14. August 2020 um 8:27 Uhr

1646976613 884 Wie kann ich uber eine Aufzahlung iterieren
zdf

#include <iostream>
#include <algorithm>

namespace MyEnum
{
  enum Type
  {
    a = 100,
    b = 220,
    c = -1
  };

  static const Type All[] = { a, b, c };
}

void fun( const MyEnum::Type e )
{
  std::cout << e << std::endl;
}

int main()
{
  // all
  for ( const auto e : MyEnum::All )
    fun( e );

  // some
  for ( const auto e : { MyEnum::a, MyEnum::b } )
    fun( e );

  // all
  std::for_each( std::begin( MyEnum::All ), std::end( MyEnum::All ), fun );

  return 0;
}

  • Danke! Beachten Sie, dass, wenn Sie Dateien/Klassen kreuzen und die MS-Kompatibilität Probleme mit Header-deklarierten nicht ganzzahligen Konstanten verursacht, es unter meinem Compiler hilft, die Größe explizit in den Typ im Header einzufügen: static const Type All[3]; und dann kann ich in der Quelle initialisieren: const MyEnum::Type MyEnum::All[3] = { a, b, c }; Davor wurde ich unausstehlich Error in range-based for... Fehler (weil das Array eine unbekannte Größe hatte). Habe das dank einer verwandten Antwort herausgefunden

    – Salbei

    4. März 2015 um 5:47 Uhr


  • Die Array-Version ist sehr kopier- und paste-freundlich. Die befriedigendste Antwort ist außerdem “NEIN” oder “nur für sequentielle”. Wahrscheinlich sogar makrofreundlich.

    – Paul Neves

    29. September 2016 um 15:14 Uhr


  • Dies könnte eine gute Lösung für Aufzählungen mit einer kleinen Anzahl von Elementen sein, aber für Aufzählungen mit einer großen Anzahl von Elementen muss es nicht gut passen.

    – kato2

    4. September 2019 um 15:48 Uhr

1646976614 231 Wie kann ich uber eine Aufzahlung iterieren
Francesco Chemolli

Mit c++11 gibt es tatsächlich eine Alternative: das Schreiben eines einfachen vorlagenbasierten benutzerdefinierten Iterators.

Nehmen wir an, Ihre Aufzählung ist

enum class foo {
  one,
  two,
  three
};

Dieser generische Code wird den Trick ziemlich effizient erledigen – platzieren Sie ihn in einem generischen Header, er wird Ihnen für jede Aufzählung dienen, über die Sie möglicherweise iterieren müssen:

#include <type_traits>
template < typename C, C beginVal, C endVal>
class Iterator {
  typedef typename std::underlying_type<C>::type val_t;
  int val;
public:
  Iterator(const C & f) : val(static_cast<val_t>(f)) {}
  Iterator() : val(static_cast<val_t>(beginVal)) {}
  Iterator operator++() {
    ++val;
    return *this;
  }
  C operator*() { return static_cast<C>(val); }
  Iterator begin() { return *this; } //default ctor is good
  Iterator end() {
      static const Iterator endIter=++Iterator(endVal); // cache it
      return endIter;
  }
  bool operator!=(const Iterator& i) { return val != i.val; }
};

Du musst es spezialisieren

typedef Iterator<foo, foo::one, foo::three> fooIterator;

Und dann können Sie mit range-for iterieren

for (foo i : fooIterator() ) { //notice the parentheses!
   do_stuff(i);
}

Die Annahme, dass Sie keine Lücken in Ihrer Aufzählung haben, ist immer noch wahr; Es gibt keine Annahme über die Anzahl der Bits, die tatsächlich benötigt werden, um den Enum-Wert zu speichern (dank std::underlying_type)

  • @Lepe? Sie erstellen einfach eine andere Typedef für eine andere Aufzählung.

    – Andreas Lazarus

    24. September 2015 um 21:49 Uhr

  • @lepe Das ist so, als würde man das sagen std::vector ist nicht generisch, weil std::vector<foo> gebunden ist foo.

    – Kyle Strand

    2. Dezember 2015 um 21:15 Uhr

  • typedef Iterator<color, color::green, color::red> colorIterator; Stellen Sie sicher, dass Sie verstehen, wie die Vorlageninstanziierungen funktionieren.

    – Andreas Lazarus

    3. Dezember 2015 um 17:12 Uhr

  • Oh, ich verstehe das Problem — foo operator*() { ... sollte sein C operator*() { ....

    – Kyle Strand

    3. Dezember 2015 um 23:08 Uhr

  • @KyleStrand: Du hast es! das macht jetzt total sinn. Soll der Code aktualisiert werden? Danke an alle für eure Erklärungen.

    – Lepe

    4. Dezember 2015 um 0:44 Uhr

zu kompliziert diese Lösung, ich mag das:

enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3};

const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary };

for (NodePosition pos : NodePositionVector) {
...
}

Wenn Ihre Aufzählung mit 0 beginnt und das Inkrement immer 1 ist.

enum enumType 
{ 
    A = 0,
    B,
    C,
    enumTypeEnd
};

for(int i=0; i<enumTypeEnd; i++)
{
   enumType eCurrent = (enumType) i;            
}

Wenn nicht, denke ich, ist der einzige Grund, so etwas wie a zu erstellen

vector<enumType> vEnums;

Fügen Sie die Elemente hinzu und verwenden Sie normale Iteratoren….

  • Der Operator “<" ist für Aufzählungen nicht verfügbar.

    – Matt

    11. August 2021 um 19:00 Uhr

  • i<enumTypeEnd führt auch eine implizite Umwandlung durch

    – Trommel

    3. November 2021 um 10:47 Uhr

Ich mache das oft so

    enum EMyEnum
    {
        E_First,
        E_Orange = E_First,
        E_Green,
        E_White,
        E_Blue,
        E_Last
    }

    for (EMyEnum i = E_First; i < E_Last; i = EMyEnum(i + 1))
    {}

oder wenn nicht sukzessive, aber mit regelmäßigem Schritt (z. B. Bitmerker)

    enum EAnimalCaps
    {
        E_None    = 0,
        E_First   = 0x1,
        E_CanFly  = E_First,
        E_CanWalk = 0x2
        E_CanSwim = 0x4,
        E_Last
    }
    
    class MyAnimal
    {
       EAnimalCaps m_Caps;
    }

    class Frog
    {
        Frog() : 
            m_Caps(EAnimalCaps(E_CanWalk | E_CanSwim))
        {}
    }

    for (EAnimalCaps= E_First; i < E_Last; i = EAnimalCaps(i << 1))
    {}

  • Der Operator “<" ist für Aufzählungen nicht verfügbar.

    – Matt

    11. August 2021 um 19:00 Uhr

  • i<enumTypeEnd führt auch eine implizite Umwandlung durch

    – Trommel

    3. November 2021 um 10:47 Uhr

1646976614 523 Wie kann ich uber eine Aufzahlung iterieren
Corey Trager

Mit einer Aufzählung geht das nicht. Vielleicht ist eine Aufzählung nicht die beste Lösung für Ihre Situation.

Eine übliche Konvention besteht darin, den letzten Aufzählungswert so zu benennen wie MAX und diesen zu verwenden, um eine Schleife mit einem int zu steuern.

  • Hier gibt es mehrere Beispiele, die das Gegenteil zeigen. I Ihrer eigenen Aussage widersprechen Sie sich selbst (zweite Zeile).

    – Niki

    31. Dezember 2019 um 12:54 Uhr

989980cookie-checkWie kann ich über eine Aufzählung iterieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy