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
?
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
?
Die typische Vorgehensweise 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 das Enum Last
soll bei der Iteration übersprungen werden. Die Verwendung dieser "Fälschung" Last
enum, müssen Sie nicht jedes Mal, wenn Sie eine neue enum hinzufügen wollen, Ihre Abbruchbedingung in der for-Schleife auf die letzte "echte" enum aktualisieren. Wenn Sie später weitere Enums hinzufügen möchten, fügen Sie sie einfach vor Last ein. Die Schleife in diesem Beispiel funktioniert trotzdem.
Das funktioniert natürlich nicht, wenn die Enum-Werte angegeben werden:
enum Foo {
One = 1,
Two = 9,
Three = 4,
Last
};
Dies verdeutlicht, dass eine Aufzählung nicht wirklich dazu gedacht ist, sie zu durchlaufen. Die typische Art, mit einer Aufzählung umzugehen, ist die Verwendung in einer switch-Anweisung.
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 wollen, stopfen Sie die Aufzählungswerte in einen Vektor und iterieren Sie über diesen. Dadurch werden auch die angegebenen Enum-Werte korrekt behandelt.
#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;
}
Mit C++11 gibt es tatsächlich eine Alternative: das Schreiben eines einfachen benutzerdefinierten Iterators mit Vorlage.
Nehmen wir an, Ihre Aufzählung lautet
enum class foo {
one,
two,
three
};
Dieser generische Code wird den Trick tun, ziemlich effizient - Platz in einem generischen Header, wird es Ihnen für jede Enum Sie brauchen, um über iterate dienen:
#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 kann man 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 Aufzählungswert zu speichern (dank std::underlying_type)
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, sondern mit regelmäßigem Schritt (z. B. Bit-Flags)
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))
{}
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.