429 Stimmen

Wie kann ich über eine Aufzählung iterieren?

Mir ist gerade aufgefallen, dass man die Standard-Mathematik-Operatoren nicht auf eine enum wie zum Beispiel ++ o += .

Wie kann man also am besten durch alle Werte in einer C++-Datei iterieren? enum ?

16voto

João Augusto Punkte 2267

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, gibt es wohl nur eine Möglichkeit, so etwas wie eine

vector<enumType> vEnums;

die Elemente hinzufügen und normale Iteratoren verwenden....

14voto

marski Punkte 411

Die Annahme, dass die Aufzählung fortlaufend nummeriert ist, ist fehleranfällig. Außerdem möchten Sie vielleicht nur über ausgewählte Aufzählungszeichen iterieren. Wenn diese Teilmenge klein ist, könnte eine explizite Schleifenbildung eine elegante Wahl sein:

enum Item { Man, Wolf, Goat, Cabbage }; // or enum class

for (auto item : {Wolf, Goat, Cabbage}) { // or Item::Wolf, ...
    // ...
}

9voto

Riot Punkte 14594

Etwas, das in den anderen Antworten nicht behandelt wurde = wenn Sie stark typisierte C++11-Enums verwenden, können Sie ++ o + int über sie. In diesem Fall ist eine etwas chaotischere Lösung erforderlich:

enum class myenumtype {
  MYENUM_FIRST,
  MYENUM_OTHER,
  MYENUM_LAST
}

for(myenumtype myenum = myenumtype::MYENUM_FIRST;
    myenum != myenumtype::MYENUM_LAST;
    myenum = static_cast<myenumtype>(static_cast<int>(myenum) + 1)) {

  do_whatever(myenum)

}

9voto

nathanfranke Punkte 453

Casting der Variablen in eine int& ermöglicht es Ihnen, den Wert zu erhöhen, ohne dass die Schrift unleserlich wird.

#include <iostream>

enum MyEnum
{
    ONE,
    TWO,
    THREE,
    FOUR,
};

int main()
{
    for (MyEnum v = MyEnum::ONE; v <= MyEnum::FOUR; ++(int&)v)
    {
        std::cout<<v<<std::endl;
    }

    return 0;
}

0
1
2
3

8voto

Eponymous Punkte 5001
enum class A {
    a0=0, a3=3, a4=4
};
constexpr std::array<A, 3> ALL_A {A::a0, A::a3, A::a4}; // constexpr is important here

for(A a: ALL_A) {
  if(a==A::a0 || a==A::a4) std::cout << static_cast<int>(a);
}

A constexpr std::array kann sogar nicht-sequenzielle Enums durchlaufen, ohne dass das Array vom Compiler instanziiert wird. Dies hängt von Dingen wie der Optimierungsheuristik des Compilers und davon ab, ob Sie die Adresse des Arrays übernehmen.

Bei meinen Experimenten habe ich festgestellt, dass g++ 9.1 mit -O3 wird das obige Array wegoptimieren, wenn es 2 nicht-sequenzielle Werte oder ziemlich viele sequentielle Werte gibt (ich habe bis zu 6 getestet). Aber es tut dies nur, wenn Sie eine if Anweisung. (Ich habe eine Anweisung ausprobiert, die einen ganzzahligen Wert vergleicht, der größer ist als alle Elemente in einem sequenziellen Array, und sie hat die Iteration eingefügt, obwohl keine ausgeschlossen wurde, aber als ich die if-Anweisung weggelassen habe, wurden die Werte in den Speicher geschrieben). Es wurden auch 5 Werte aus einem nicht-sequentiellen Enum in einem Fall inlined. [https://godbolt.org/z/XuGtoc\]](https://godbolt.org/z/XuGtoc]) . Ich vermute, dass dieses seltsame Verhalten auf tiefgreifende Heuristiken zurückzuführen ist, die mit Caches und Verzweigungsvorhersagen zu tun haben.

Hier ist ein Link zu einer einfachen Testiteration auf Godbolt die zeigt, dass das Array nicht immer instanziiert wird.

Der Preis für diese Technik ist, dass die Aufzählungselemente zweimal geschrieben werden und die beiden Listen synchron bleiben.

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