C++ 如何遍历枚举?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/261963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I iterate over an enum?
提问by Adam
I just noticed that you can not use standard math operators on an enum such as ++ or +=
我只是注意到你不能在枚举上使用标准的数学运算符,比如 ++ 或 +=
So what is the best way to iterate through all of the values in a C++ enum?
那么遍历 C++ 枚举中所有值的最佳方法是什么?
采纳答案by andreas buykx
The typical way is as follows:
典型的方法如下:
enum Foo {
One,
Two,
Three,
Last
};
for ( int fooInt = One; fooInt != Last; fooInt++ )
{
Foo foo = static_cast<Foo>(fooInt);
// ...
}
Please note, the enum Last
is meant to be skipped by the iteration. Utilizing this "fake" Last
enum, you don't have to update your terminating condition in the for loop to the last "real" enum each time you want to add a new enum.
If you want to add more enums later, just add them before Last. The loop in this example will still work.
请注意,枚举Last
旨在被迭代跳过。使用这个“假”Last
枚举,您不必在每次要添加新枚举时将 for 循环中的终止条件更新为最后一个“真实”枚举。如果您想稍后添加更多枚举,只需在 Last 之前添加它们。本例中的循环仍然有效。
Of course, this breaks down if the enum values are specified:
当然,如果指定了枚举值,这会崩溃:
enum Foo {
One = 1,
Two = 9,
Three = 4,
Last
};
This illustrates that an enum is not really meant to iterate through. The typical way to deal with an enum is to use it in a switch statement.
这说明枚举并不是真的要迭代。处理枚举的典型方法是在 switch 语句中使用它。
switch ( foo )
{
case One:
// ..
break;
case Two: // intentional fall-through
case Three:
// ..
break;
case Four:
// ..
break;
default:
assert( ! "Invalid Foo enum value" );
break;
}
If you really want to enumerate, stuff the enum values in a vector and iterate over that. This will properly deal with the specified enum values as well.
如果您真的想枚举,请将枚举值填充到向量中并对其进行迭代。这也将正确处理指定的枚举值。
回答by 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;
}
回答by Jo?o Augusto
If your enum starts with 0 and the increment is always 1.
如果您的枚举以 0 开头并且增量始终为 1。
enum enumType
{
A = 0,
B,
C,
enumTypeEnd
};
for(int i=0; i<enumTypeEnd; i++)
{
enumType eCurrent = (enumType) i;
}
If not I guess the only why is to create something like a
如果不是,我想唯一的原因是创建类似
vector<enumType> vEnums;
add the items, and use normal iterators....
添加项目,并使用普通迭代器....
回答by Francesco Chemolli
With c++11, there actually is an alternative: writing a simple templatized custom iterator.
使用 c++11,实际上还有一个替代方案:编写一个简单的模板化自定义迭代器。
let's assume your enum is
让我们假设您的枚举是
enum class foo {
one,
two,
three
};
This generic code will do the trick, quite efficiently - place in a generic header, it'll serve you for any enum you may need to iterate over:
这段通用代码将非常有效地解决问题 - 放置在通用标头中,它将为您可能需要迭代的任何枚举提供服务:
#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; }
};
You'll need to specialize it
你需要专攻它
typedef Iterator<foo, foo::one, foo::three> fooIterator;
And then you can iterate using range-for
然后你可以使用 range-for 进行迭代
for (foo i : fooIterator() ) { //notice the parentheses!
do_stuff(i);
}
The assumption that you don't have gaps in your enum is still true; there is no assumption on the number of bits actually needed to store the enum value (thanks to std::underlying_type)
枚举中没有间隙的假设仍然成立;没有假设存储枚举值实际需要的位数(感谢 std::underlying_type)
回答by Enzojz
too much complicated these solution, i do like that :
这些解决方案太复杂了,我喜欢这样:
enum NodePosition { Primary = 0, Secondary = 1, Tertiary = 2, Quaternary = 3};
const NodePosition NodePositionVector[] = { Primary, Secondary, Tertiary, Quaternary };
for (NodePosition pos : NodePositionVector) {
...
}
回答by Niki
I often do it like that
我经常这样做
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))
{}
or if not successive, but with regular step (e.g. bit flags)
或者如果不是连续的,但有规律的步骤(例如位标志)
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))
{}
回答by Corey Trager
You can't with an enum. Maybe an enum isn't the best fit for your situation.
你不能用枚举。也许枚举不适合您的情况。
A common convention is to name the last enum value something like MAX and use that to control a loop using an int.
一个常见的约定是将最后一个枚举值命名为类似 MAX 的名称,并使用它来控制使用 int 的循环。
回答by Riot
Something that hasn't been covered in the other answers = if you're using strongly typed C++11 enums, you cannot use ++
or + int
on them. In that case, a bit of a messier solution is required:
其他答案中未涵盖的内容 = 如果您使用的是强类型 C++11 枚举,则不能在它们上使用++
或+ int
。在这种情况下,需要一些更混乱的解决方案:
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)
}
回答by Mikhail Semenov
You can try and define the following macro:
您可以尝试定义以下宏:
#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))
Now you can use it:
现在你可以使用它:
enum Count { zero, one, two, three };
for_range (Count, c, zero, three)
{
cout << "forward: " << c << endl;
}
It can be used to iterate backwards and forwards through unsigned, integers, enums and chars:
它可用于通过无符号、整数、枚举和字符向后和向前迭代:
for_range (unsigned, i, 10,0)
{
cout << "backwards i: " << i << endl;
}
for_range (char, c, 'z','a')
{
cout << c << endl;
}
Despite its awkward definition it is optimized very well. I looked at disassembler in VC++. The code is extremely efficient. Don't be put off but the three for statements: the compiler will produce only one loop after optimization! You can even define enclosed loops:
尽管它的定义很笨拙,但它优化得很好。我在 VC++ 中查看了反汇编程序。该代码非常有效。不要推迟三个 for 语句:编译器在优化后只会产生一个循环!您甚至可以定义封闭循环:
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;
}
You obviously cannot iterate through enumerated types with gaps.
您显然无法遍历具有间隙的枚举类型。
回答by JohnMcG
You can also overload the increment/decrement operators for your enumerated type.
您还可以为您的枚举类型重载递增/递减运算符。