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.
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:
enumFoo{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.
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.
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>namespaceMyEnum{enumType{
a =100,
b =220,
c =-1};staticconstTypeAll[]={ a, b, c };}void fun(constMyEnum::Type e ){
std::cout << e << std::endl;}int main(){// allfor(constauto e :MyEnum::All)
fun( e );// somefor(constauto e :{MyEnum::a,MyEnum::b })
fun( e );// all
std::for_each( std::begin(MyEnum::All), std::end(MyEnum::All), fun );return0;}
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.
Mit c ++ 11 gibt es tatsächlich eine Alternative: Schreiben eines einfachen benutzerdefinierten Iterators mit Vorlagen.
Nehmen wir an, Ihre Aufzählung ist
enumclass 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>classIterator{typedeftypename 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)){}Iteratoroperator++(){++val;return*this;}
C operator*(){returnstatic_cast<C>(val);}Iterator begin(){return*this;}//default ctor is goodIterator end(){staticconstIterator endIter=++Iterator(endVal);// cache itreturn endIter;}booloperator!=(constIterator& i){return val != i.val;}};
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).
@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.
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
enumEMyEnum{
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)
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.
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:
enumCount{ 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(unsignedint, j,4,0){
p[i][j]=static_cast<unsigned>(i)+j;}
Sie können offensichtlich keine aufgezählten Typen mit Lücken durchlaufen.
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.
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:
enumItem{Man,Wolf,Goat,Cabbage};// or enum classfor(auto item :{Wolf,Goat,Cabbage}){// or Item::Wolf, ...// ...}
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:
enumColour{Red,Green,Blue};constColourLastColour=Blue;Colour co(0);while(true){// do stuff with co// ...if(co ==LastColour)break;
co =Colour(co+1);}
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.
enumBar{One=1,Two,Three,End_Bar// Marker for end of enum; };for(Bar foo =One; foo <End_Bar; foo =Bar(foo +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
enumclass A {
a0=0, a3=3, a4=4};constexpr std::array<A,3> ALL_A {A::a0, A::a3, A::a4};// constexpr is important herefor(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.
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>enumclassColors{red, green, blue};Colors&operator++(Colors&c,int){switch(c){caseColors::red:return c=Colors::green;caseColors::green:return c=Colors::blue;caseColors::blue:return c=Colors::red;// managing overflowdefault: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;return0;}
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.
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.
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
typedefenum{
first =2,
second =6,
third =17}MyEnum;staticconstint enumItems[]={
first,
second,
third
}staticconstintEnumLength=sizeof(enumItems)/sizeof(int);for(int i =0; i <EnumLength; i++){//Do something with enumItems[i]}
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ö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:
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:
enumMyEnumType{Hay=12,Grass=42,Beer=39};
dann Array erstellen:
intArray[]={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.
int
nicht abzudecken, das möglicherweise nicht groß genug ist! ([C++03: 7.2/5]
)operator++
Aufzählungen definieren ; Sie können dies jedoch tunfor(Enum_E e = (Enum_E)0; e < ENUM_COUNT; e++)
. Beachten Sie Guss haben0
zu ,Enum_E
weil C ++ verbietet Zuweisungsoperatoren auf Aufzählungen.Antworten:
Der typische Weg ist wie folgt:
Bitte beachten Sie, dass die Aufzählung
Last
von der Iteration übersprungen werden soll. Wenn Sie diese "gefälschte"Last
Aufzä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:
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.
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.
quelle
UNKNOWN = 0
. Außerdem würde ich vorschlagen, dendefault
Fall 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 dasUNKNOWN
Feld verwenden, um Inkompatibilitäten zu erkennen.quelle
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 unangenehmeError in range-based for...
Fehler erhalten (weil das Array eine unbekannte Größe hatte). Ich habe es dank einer ähnlichen Antwort herausgefundenWenn Ihre Aufzählung mit 0 beginnt und das Inkrement immer 1 ist.
Wenn nicht, denke ich, ist der einzige Grund, so etwas wie ein zu erstellen
Fügen Sie die Elemente hinzu und verwenden Sie normale Iteratoren.
quelle
Mit c ++ 11 gibt es tatsächlich eine Alternative: Schreiben eines einfachen benutzerdefinierten Iterators mit Vorlagen.
Nehmen wir an, Ihre Aufzählung ist
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:
Sie müssen es spezialisieren
Und dann können Sie mit range-for iterieren
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).
quelle
std::vector
das nicht generisch ist, weilstd::vector<foo>
es daran gebunden istfoo
.typedef Iterator<color, color::green, color::red> colorIterator;
Stellen Sie sicher, dass Sie verstehen, wie die Vorlageninstanziierungen funktionieren.foo operator*() { ...
sollte es seinC operator*() { ...
.zu kompliziert diese Lösung, ich mag das:
quelle
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.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öchtenauto
aus irgendeinem Grund nicht . Die meisten Range-for
User verwendenauto
AFAICTIch mache es oft so
oder wenn nicht aufeinanderfolgend, aber mit regulärem Schritt (zB Bitflags)
quelle
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.
quelle
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+ int
auf sie. In diesem Fall ist eine etwas chaotischere Lösung erforderlich:quelle
Sie können versuchen, das folgende Makro zu definieren:
Jetzt können Sie es verwenden:
Es kann verwendet werden, um durch vorzeichenlose Ganzzahlen, Aufzählungen und Zeichen vorwärts und rückwärts zu iterieren:
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:
Sie können offensichtlich keine aufgezählten Typen mit Lücken durchlaufen.
quelle
_A1
ist kein zulässiger Name, sondern ein führender Unterstrich mit einem folgenden Großbuchstaben.Sie können auch die Inkrementierungs- / Dekrementierungsoperatoren für Ihren Aufzählungstyp überladen.
quelle
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:
quelle
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:
quelle
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.
quelle
foo = Bar(foo + 1)
.A
constexpr std::array
kann 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-O3
das 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 eineif
Erklä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.
quelle
In Bjarne Stroustrups C ++ - Programmiersprachenbuch können Sie lesen, dass er vorschlägt, das
operator++
für Ihre spezifischen zu überladenenum
.enum
sind benutzerdefinierte Typen und Überladungsoperatoren sind in der Sprache für diese spezifischen Situationen vorhanden.Sie können Folgendes codieren:
Testcode: http://cpp.sh/357gb
Kümmere dich darum, dass ich benutze
enum class
. Code funktioniert auch gut mitenum
. Aber ich bevorzuge es,enum class
da sie stark typisiert sind und verhindern können, dass wir beim Kompilieren Fehler machen.quelle
enum
. Es war keine architektonische Frage. Ich glaube nicht, dass C ++ 2013 eine Science-Fiction war.Für MS-Compiler:
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
typeof
anstelle von verwendendecltype
, aber ich habe diesen Compiler im Moment nicht zur Hand, um sicherzustellen, dass er kompiliert wird.quelle
decltype
Standard-C ++ geschrieben, daher sollten Sie das veraltetetypeof
aus dem alten GCC nicht empfehlen . Vage neue GCC-Griffedecltype
ganz 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, umstatic_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ötigtenum class
. Alternativ können Operatoren proenum
Typ (TIL) überlastet werdenquelle
constexpr static const int enumItems[]
C ++ hat keine Selbstbeobachtung, daher können Sie solche Dinge zur Laufzeit nicht bestimmen.
quelle
Wenn Sie wüssten, dass die Aufzählungswerte sequentiell sind, z. B. die Qt: Key-Aufzählung, können Sie:
Es funktioniert wie erwartet.
quelle
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:
dann Array erstellen:
Dies bricht unabhängig von den Ints in der Darstellung nicht zusammen, solange -1 check natürlich nicht mit einem der Elemente kollidiert.
quelle