Wie kann ich über eine Aufzählung iterieren?

304

Ich habe gerade bemerkt, dass Sie keine Standard-Mathematikoperatoren für eine Aufzählung wie ++ oder + = verwenden können

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

Adam
quelle
2
Einer von vielen Ansätzen: Wenn Enum einfach nicht genug ist: Aufzählungsklassen für C ++ . Und wenn Sie etwas Kapselteres wünschen, probieren Sie diesen Ansatz von James Kanze aus.
Don Wakefield
Verknüpfte Elemente haben einige interessante Antworten.
Tony
Diese Antworten scheinen das Problem intnicht abzudecken, das möglicherweise nicht groß genug ist! ( [C++03: 7.2/5])
Leichtigkeitsrennen im Orbit
Interessanterweise können Sie operator++Aufzählungen definieren ; Sie können dies jedoch tun for(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++). Beachten Sie Guss haben 0zu , Enum_Eweil C ++ verbietet Zuweisungsoperatoren auf Aufzählungen.
weberc2
Wenn es einen Operator für die Kompilierungszeit gäbe, der ähnlich wie sizeof funktioniert und ein std :: initializer_list-Literal ausgeben könnte, das aus den Werten der Aufzählung besteht, hätten wir eine Lösung und würden keinen Laufzeitaufwand verursachen.
Jbruni

Antworten:

263

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, dass die Aufzählung Lastvon der Iteration übersprungen werden soll. Wenn Sie diese "gefälschte" LastAufzählung verwenden, 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 diese einfach vor dem letzten hinzu. Die Schleife in diesem Beispiel funktioniert weiterhin.

Dies bricht natürlich zusammen, wenn die Aufzählungswerte angegeben werden:

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

Dies zeigt, dass eine Aufzählung nicht wirklich zum Durchlaufen gedacht ist. Der typische Weg, 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 Aufzählungswerte ordnungsgemäß behandelt.

andreas buykx
quelle
13
Beachten Sie, dass Sie im ersten Teil des Beispiels, wenn Sie 'i' als Foo-Enum und nicht als int verwenden möchten, statisch umwandeln müssen: static_cast <Foo> (i)
Clayton
5
Außerdem überspringen Sie Last in the Loop. Sollte <= Last sein
Tony
20
@ Tony Last soll übersprungen werden. Wenn Sie später weitere Aufzählungen hinzufügen möchten, fügen Sie diese vor Last ... hinzu. Die Schleife im ersten Beispiel funktioniert weiterhin. Wenn Sie eine "gefälschte" letzte Aufzählung verwenden, müssen Sie Ihre Abschlussbedingung 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
Außer jetzt haben Sie tatsächlich Speicher zugewiesen, wenn eine Aufzählung, sofern sie nicht indiziert und streng kontinuierlich ist, diese Aufgabe ausführen kann, ohne Speicher zuzuweisen.
Wolke
1
Beachten Sie, dass Sie einen Wert definieren sollten, damit diese Aufzählungsdefinition für Aktualisierungen sicher ist UNKNOWN = 0. Außerdem würde ich vorschlagen, den defaultFall beim Umschalten von Enum-Werten einfach zu löschen, da dadurch möglicherweise Fälle ausgeblendet werden, in denen die Behandlung von Werten bis zur Laufzeit vergessen wurde. Stattdessen sollte man alle Werte fest codieren und das UNKNOWNFeld verwenden, um Inkompatibilitäten zu erkennen.
Benjamin Bannier
53
#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;
}
zdf
quelle
Vielen Dank! Beachten Sie, dass es unter meinem Compiler hilfreich ist, die Größe explizit in den Typ im Header einzufügen, wenn Sie Dateien / Klassen kreuzen und MS-Kompatibilität Probleme mit vom Header deklarierten Nicht-Integer-Konstanten verursacht: static const Type All[3];und dann bin ich in der Lage So initialisieren Sie in der Quelle: const MyEnum::Type MyEnum::All[3] = { a, b, c }; Vorher habe ich unangenehme Error in range-based for...Fehler erhalten (weil das Array eine unbekannte Größe hatte). Ich habe es dank einer ähnlichen Antwort herausgefunden
Salbei
1
Die Array-Version ist sehr freundlich zum Kopieren und Einfügen. Die zufriedenstellendste Antwort außerdem "NEIN" oder "nur für sequentielle". Wahrscheinlich sogar makrofreundlich.
Paulo Neves
1
Dies mag 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
20

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 ein zu erstellen

vector<enumType> vEnums;

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

João Augusto
quelle
19

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

Nehmen wir an, Ihre Aufzählung ist

enum class foo {
  one,
  two,
  three
};

Dieser generische Code erledigt den Trick recht effizient - in einen generischen Header einfügen, dient er Ihnen für jede Aufzählung, die Sie möglicherweise durchlaufen 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; }
};

Sie müssen 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 zum Speichern des Enum-Werts benötigt werden (dank std :: zugrunde liegender_Typ).

Francesco Chemolli
quelle
1
@lepe? Sie erstellen einfach ein anderes Typedef für eine andere Aufzählung.
Andrew Lazarus
2
@lepe Das ist so, als würde man sagen, dass std::vectordas nicht generisch ist, weil std::vector<foo>es daran gebunden ist foo.
Kyle Strand
1
typedef Iterator<color, color::green, color::red> colorIterator;Stellen Sie sicher, dass Sie verstehen, wie die Vorlageninstanziierungen funktionieren.
Andrew Lazarus
2
Oh, ich sehe das Problem - foo operator*() { ...sollte es sein C operator*() { ....
Kyle Strand
1
@ KyleStrand: Du hast es verstanden! das macht jetzt total sinn. Sollte der Code aktualisiert werden? Vielen Dank an alle für Ihre Erklärungen.
Lepe
16

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) {
...
}
Enzojz
quelle
Ich weiß nicht, warum dies abgelehnt wurde. Es ist eine vernünftige Lösung.
Paul Brannan
11
Ich gehe davon aus, dass die Einträge an zwei Stellen gepflegt werden müssen.
Ameise
Erlaubt C ++ die for (NodePosition pos : NodePositionVector)Syntax? Soweit mir bekannt ist, handelt es sich um Java-Syntax, und Sie benötigen Iteratoren in C ++, um etwas Äquivalentes zu tun.
Thegreatjedi
3
@thegreatjedi Seit C ++ 11 können Sie noch einfacher: für (auto pos: NodePositionVector) {..}
Enzojz
@thegreatjedi Es wäre schneller gewesen, ein Testprogramm zu suchen oder sogar zu kompilieren, als diese Frage zu stellen. Aber ja, seit C ++ 11 ist es eine vollkommen gültige C ++ - Syntax, die der Compiler in den äquivalenten (und weitaus ausführlicheren / weniger abstrahierenden) Code übersetzt, normalerweise über Iteratoren. siehe cppreference . Und wie Enzojz sagte, wurde auch C ++ 11 hinzugefügt auto, sodass Sie den Typ der Elemente nicht explizit deklarieren müssen, es sei denn, Sie (A) müssen einen Konvertierungsoperator verwenden oder (B) möchten autoaus irgendeinem Grund nicht . Die meisten Range- forUser verwenden autoAFAICT
underscore_d
9

Ich mache es 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 aufeinanderfolgend, aber mit regulärem Schritt (zB Bitflags)

    enum EAnimalCaps
    {
        E_First,
        E_None    = E_First,
        E_CanFly  = 0x1,
        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))
    {}
Niki
quelle
Aber was nützt es, die Werte bitweise zu drucken?
Anu
1
Verwenden von Aufzählungen zum Erstellen von Bitmasken. Kombinieren Sie z. B. mehrere Optionen in einer Variablen und testen Sie dann mit dem FOR für jede Option. Mein Beitrag wurde mit einem besseren Beispiel korrigiert.
Niki
Ich kann es immer noch nicht verwenden (und Ihr Beitrag zeigt immer noch das alte Beispiel)! Die Verwendung von Enum als Bitmasken ist sehr hilfreich, konnte aber die Punkte nicht verbinden! Könnten Sie bitte in Ihrem Beispiel etwas näher darauf eingehen, können Sie auch den zusätzlichen Code eingeben.
Anu
@anu Sorry hat deinen Kommentar nicht gesehen. Froschklasse als Bitmaskenbeispiel hinzugefügt
Niki
8

Sie können nicht mit einer Aufzählung. Vielleicht passt eine Aufzählung nicht zu Ihrer Situation.

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

Corey Trager
quelle
Hier gibt es mehrere Beispiele, die das Gegenteil demonstrieren. Ich Ihre eigene Aussage, die Sie sich widersprechen (zweite Zeile).
Niki
6

Etwas , das nicht in den anderen Antworten zurückgelegt hat = wenn Sie stark typisierte C ++ 11 Aufzählungen verwenden, können Sie nicht verwenden können , ++oder + intauf 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)

}
Randalieren
quelle
3
... aber C ++ 11 führt den Bereich ein, der darauf basiert und in anderen Antworten gezeigt wird. :-)
Salbei
5

Sie können versuchen, das folgende Makro zu definieren:

#define for_range(_type, _param, _A1, _B1) for (bool _ok = true; _ok;)\
for (_type _start = _A1, _finish = _B1; _ok;)\
    for (int _step = 2*(((int)_finish)>(int)_start)-1;_ok;)\
         for (_type _param = _start; _ok ; \
 (_param != _finish ? \
           _param = static_cast<_type>(((int)_param)+_step) : _ok = false))

Jetzt können Sie es verwenden:

enum Count { zero, one, two, three }; 

    for_range (Count, c, zero, three)
    {
        cout << "forward: " << c << endl;
    }

Es kann verwendet werden, um durch vorzeichenlose Ganzzahlen, Aufzählungen und Zeichen vorwärts und rückwärts zu iterieren:

for_range (unsigned, i, 10,0)
{
    cout << "backwards i: " << i << endl;
}


for_range (char, c, 'z','a')
{
    cout << c << endl;
}

Trotz seiner umständlichen Definition ist es sehr gut optimiert. Ich habe mir Disassembler in VC ++ angesehen. Der Code ist äußerst effizient. Lassen Sie sich nicht abschrecken, sondern die drei for-Anweisungen: Der Compiler erzeugt nach der Optimierung nur eine Schleife! Sie können sogar geschlossene Schleifen definieren:

unsigned p[4][5];

for_range (Count, i, zero,three)
    for_range(unsigned int, j, 4, 0)
    {   
        p[i][j] = static_cast<unsigned>(i)+j;
    }

Sie können offensichtlich keine aufgezählten Typen mit Lücken durchlaufen.

Mikhail Semenov
quelle
1
Das ist ein wunderbarer Hack! Obwohl es für C besser geeignet ist als für C ++, könnte man sagen.
Einpoklum
3
_A1ist kein zulässiger Name, sondern ein führender Unterstrich mit einem folgenden Großbuchstaben.
Martin Ueding
3

Sie können auch die Inkrementierungs- / Dekrementierungsoperatoren für Ihren Aufzählungstyp überladen.

JohnMcG
quelle
1
Sie können keine Operatoren für C- oder C ++ - Aufzählungstypen überladen. Es sei denn, Sie erstellen eine Struktur / Klasse, die eine Aufzählung von Werten emuliert.
Trevor Hickey
2
C ++ ermöglicht das Überladen von Operatoren in Aufzählungen. Siehe stackoverflow.com/questions/2571456/… .
Arch D. Robison
Das Überladen des Inkrements / Dekrements erfordert eine Entscheidung darüber, was bei einem Überlauf zu tun ist
gleichnamig
3

Die Annahme, dass die Aufzählung fortlaufend nummeriert ist, ist fehleranfällig. Darüber hinaus möchten Sie möglicherweise nur über ausgewählte Enumeratoren iterieren. Wenn diese Teilmenge klein ist, kann es eine elegante Wahl sein, sie explizit zu durchlaufen:

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

for (auto item : {Wolf, Goat, Cabbage}) { // or Item::Wolf, ...
    // ...
}
Marski
quelle
Dies ist eine schöne Option, denke ich. Muss Teil einer neueren C ++ - Spezifikation sein, als ich sie verwendet habe, als ich die Frage gestellt habe, die ich vermute?
Adam
Ja. Es iteriert über eine std :: initializer_list <Item>. Link .
Marski
2

Wenn Sie Ihre Aufzählung nicht mit einem endgültigen COUNT-Element verschmutzen möchten (denn wenn Sie die Aufzählung möglicherweise auch in einem Switch verwenden, werden Sie vom Compiler vor einem fehlenden COUNT-Fall gewarnt :), können Sie Folgendes tun:

enum Colour {Red, Green, Blue};
const Colour LastColour = Blue;

Colour co(0);
while (true) {
  // do stuff with co
  // ...
  if (co == LastColour) break;
  co = Colour(co+1);
}
Niels Holst
quelle
2

Hier ist eine andere Lösung, die nur für zusammenhängende Aufzählungen funktioniert. Es gibt die erwartete Iteration, mit Ausnahme der Hässlichkeit im Inkrement, zu dem es gehört, da dies in C ++ fehlerhaft ist.

enum Bar {
    One = 1,
    Two,
    Three,
    End_Bar // Marker for end of enum; 
};

for (Bar foo = One; foo < End_Bar; foo = Bar(foo + 1))
{
    // ...
}
Ethan Bradford
quelle
1
Inkrementierung kann auf verkürzt werden foo = Bar(foo + 1).
HolyBlackCat
Danke, HolyBlackCat, ich habe Ihren ausgezeichneten Vorschlag aufgenommen! Ich stelle auch fest, dass Riot so ziemlich dieselbe Lösung hat, aber mit starker Typisierung (und damit ausführlicher) übereinstimmt.
Ethan Bradford
2
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::arraykann sogar nicht sequentielle Aufzählungen iterieren, ohne dass das Array vom Compiler instanziiert wird. Dies hängt beispielsweise von den Optimierungsheuristiken des Compilers ab und davon, ob Sie die Adresse des Arrays verwenden.

In meinen Experimenten habe ich festgestellt, dass g++9.1 mit -O3das obige Array optimiert, wenn es 2 nicht sequentielle Werte oder einige sequentielle Werte gibt (ich habe bis zu 6 getestet). Dies geschieht jedoch nur, wenn Sie eine ifErklärung haben. (Ich habe eine Anweisung ausprobiert, bei der ein ganzzahliger Wert verglichen wurde, der größer als alle Elemente in einem sequentiellen Array ist, und die Iteration eingefügt wurde, obwohl keine ausgeschlossen wurde. Als ich jedoch die if-Anweisung wegließ, wurden die Werte in den Speicher gestellt.) Außerdem wurde 5 eingefügt Werte aus einer nicht sequentiellen Aufzählung in [einem Fall | https://godbolt.org/z/XuGtoc] . Ich vermute, dass dieses seltsame Verhalten auf tiefe 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 besteht darin, die Enum-Elemente zweimal zu schreiben und die beiden Listen synchron zu halten.

Gleichnamig
quelle
Ich mag einfache bereichsähnliche For-Loop-Semantik und ich denke, sie wird sich noch weiter entwickeln, weshalb mir diese Lösung gefällt.
rtischer8277
2

In Bjarne Stroustrups C ++ - Programmiersprachenbuch können Sie lesen, dass er vorschlägt, das operator++für Ihre spezifischen zu überladen enum. enumsind benutzerdefinierte Typen und Überladungsoperatoren sind in der Sprache für diese spezifischen Situationen vorhanden.

Sie können Folgendes codieren:

#include <iostream>
enum class Colors{red, green, blue};
Colors& operator++(Colors &c, int)
{
     switch(c)
     {
           case Colors::red:
               return c=Colors::green;
           case Colors::green:
               return c=Colors::blue;
           case Colors::blue:
               return c=Colors::red; // managing overflow
           default:
               throw std::exception(); // or do anything else to manage the error...
     }
}

int main()
{
    Colors c = Colors::red;
    // casting in int just for convenience of output. 
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    std::cout << (int)c++ << std::endl;
    return 0;
}

Testcode: http://cpp.sh/357gb

Kümmere dich darum, dass ich benutze enum class. Code funktioniert auch gut mit enum. Aber ich bevorzuge es, enum classda sie stark typisiert sind und verhindern können, dass wir beim Kompilieren Fehler machen.

LAL
quelle
Dieser Beitrag wurde abgelehnt. Gibt es einen Grund, warum die Frage nicht beantwortet wird?
LAL
Der Grund liegt wahrscheinlich darin, dass dies architektonisch gesehen eine schreckliche Lösung ist: Sie müssen eine globale Logik schreiben, die an eine bestimmte Komponente (Ihre Aufzählung) gebunden ist. Außerdem ändert sich Ihre Aufzählung aus irgendeinem Grund, aus dem Sie gezwungen sind, Ihr + zu bearbeiten + Betreiber auch, als ein Ansatz, der für kein mittelgroßes Projekt nachhaltig ist, ist es keine Überraschung, dass er aus der Empfehlung eines Bjarne Stroustrup stammt.
Damals
Bei der ursprünglichen Frage geht es darum, einen Operator zu haben enum. Es war keine architektonische Frage. Ich glaube nicht, dass C ++ 2013 eine Science-Fiction war.
LAL
1

Für MS-Compiler:

#define inc_enum(i) ((decltype(i)) ((int)i + 1))

enum enumtype { one, two, three, count};
for(enumtype i = one; i < count; i = inc_enum(i))
{ 
    dostuff(i); 
}

Hinweis: Dies ist viel weniger Code als die einfache benutzerdefinierte Iterator-Antwort mit Vorlagen.

Sie können dies mit GCC zum Laufen bringen, indem Sie typeofanstelle von verwenden decltype, aber ich habe diesen Compiler im Moment nicht zur Hand, um sicherzustellen, dass er kompiliert wird.

user2407277
quelle
Dies wurde ~ 5 Jahre nach dem decltypeStandard-C ++ geschrieben, daher sollten Sie das veraltete typeofaus dem alten GCC nicht empfehlen . Vage neue GCC-Griffe decltypeganz gut. Es gibt noch andere Probleme: Casts im C-Stil werden nicht empfohlen und Makros sind schlechter. Richtige C ++ - Funktionen können dieselbe generische Funktionalität bieten. Dies sollte besser umgeschrieben werden, um static_cast& eine Vorlagenfunktion zu verwenden : template <typename T> auto inc_enum(T const t) { return static_cast<T>(static cast<int>(t) + 1); }. Und Casts werden nicht für Nicht- benötigt enum class. Alternativ können Operatoren pro enumTyp (TIL) überlastet werden
underscore_d
1
typedef enum{
    first = 2,
    second = 6,
    third = 17
}MyEnum;

static const int enumItems[] = {
    first,
    second,
    third
}

static const int EnumLength = sizeof(enumItems) / sizeof(int);

for(int i = 0; i < EnumLength; i++){
    //Do something with enumItems[i]
}
Justin Moloney
quelle
Diese Lösung erstellt unnötig statische Variablen im Speicher, während das Ziel von enum nur darin besteht, eine 'Maske' für eingefügte Konstanten zu erstellen
TheArquitect
Sofern nicht geändert inconstexpr static const int enumItems[]
Mohammad Kanan
0

C ++ hat keine Selbstbeobachtung, daher können Sie solche Dinge zur Laufzeit nicht bestimmen.

kͩeͣmͮpͥ ͩ
quelle
1
Können Sie mir erklären, warum "Selbstbeobachtung" erforderlich wäre, um eine Aufzählung zu durchlaufen?
Jonathan Mee
Vielleicht ist der Begriff Reflexion ?
kͩeͣmͮpͥ 8
2
Ich versuche zwei Dinge zu sagen: 1) Nach vielen anderen Antworten kann C ++ dies erreichen. Wenn Sie also sagen, dass dies nicht möglich ist, ist ein Link oder eine weitere Klarstellung erforderlich. 2) In der aktuellen Form ist dies bestenfalls ein Kommentar, sicherlich keine Antwort.
Jonathan Mee
Stimmen Sie dann meine Antwort ab - ich denke, Sie haben es mehr als gerechtfertigt
kͩeͣmͮpͥ ͩ
1
Ich werde noch einmal 2 Kommentare einholen: 1) Ich stimme nicht ab, weil ich finde, dass das Erhalten einer Abwertung die Teilnahme an der Website demotiviert. Ich finde das kontraproduktiv. 2) Ich verstehe immer noch nicht, was Sie sagen wollen, aber es klingt so Sie verstehen etwas, was ich nicht verstehe. In diesem Fall würde ich es vorziehen, wenn Sie eine heruntergestufte Antwort ausarbeiten, anstatt sie zu löschen.
Jonathan Mee
0

Wenn Sie wüssten, dass die Aufzählungswerte sequentiell sind, z. B. die Qt: Key-Aufzählung, können Sie:

Qt::Key shortcut_key = Qt::Key_0;
for (int idx = 0; etc...) {
    ....
    if (shortcut_key <= Qt::Key_9) {
        fileMenu->addAction("abc", this, SLOT(onNewTab()),
                            QKeySequence(Qt::CTRL + shortcut_key));
        shortcut_key = (Qt::Key) (shortcut_key + 1);
    }
}

Es funktioniert wie erwartet.

kcrossen
quelle
-1

Erstellen Sie einfach ein Array von Ints und durchlaufen Sie das Array, aber lassen Sie das letzte Element -1 sagen und verwenden Sie es für die Exit-Bedingung.

Wenn Aufzählung ist:

enum MyEnumType{Hay=12,Grass=42,Beer=39};

dann Array erstellen:

int Array[] = {Hay,Grass,Beer,-1};

for (int h = 0; Array[h] != -1; h++){
  doStuff( (MyEnumType) Array[h] );
}

Dies bricht unabhängig von den Ints in der Darstellung nicht zusammen, solange -1 check natürlich nicht mit einem der Elemente kollidiert.

Mathreadler
quelle