我只是注意到不能在枚举上使用标准数学运算符,如++或+=。
那么,在c++枚举中遍历所有值的最佳方法是什么?
我只是注意到不能在枚举上使用标准数学运算符,如++或+=。
那么,在c++枚举中遍历所有值的最佳方法是什么?
当前回答
您可以尝试并定义以下宏:
#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))
现在你可以使用它:
enum Count { zero, one, two, three };
for_range (Count, c, zero, three)
{
cout << "forward: " << c << endl;
}
它可以用来在无符号、整数、枚举和字符之间来回迭代:
for_range (unsigned, i, 10,0)
{
cout << "backwards i: " << i << endl;
}
for_range (char, c, 'z','a')
{
cout << c << endl;
}
尽管它的定义很尴尬,但它优化得很好。我看了一下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;
}
显然,不能在有间隙的枚举类型中进行迭代。
其他回答
使用lambda,我发现这是遍历枚举的最佳(现代)方式。 这大大提高了抽象性。 甚至可以使它成为模板,所以它适用于任何枚举。 这段代码不会给您带来clang(-tidy)问题。
#include <functional>
/// @brief Loop over all enum values where the last enum value is the invalid one
void forEachAction(std::function<void(Enum)> &&doThis) {
for (int value = 0; value = static_cast<int>(Enum::LastValue); ++value ) {
doThis(static_cast<Enum>(value ));
}
}
...
forEachAction([this](Enum value) {
... // what you want to execute for every enum
});
优点:枚举可以有你喜欢的任意顺序的任何值,并且仍然很容易迭代它们。 名称和值只定义一次,在第一个#define中。
缺点:如果你在工作中使用这个短语,你需要用一整段话来向你的同事解释。而且,必须声明内存来给你的循环提供迭代的东西是很烦人的,但我不知道有什么解决办法不限制你使用相邻值的枚举(如果枚举总是有相邻值,enum可能不会给你买那么多)。
//create a, b, c, d as 0, 5, 6, 7
#define LIST x(a) x(b,=5) x(c) x(d)
#define x(n, ...) n __VA_ARGS__,
enum MyEnum {LIST}; //define the enum
#undef x //needed
#define x(n,...) n ,
MyEnum myWalkableEnum[] {LIST}; //define an iterable list of enum values
#undef x //neatness
int main()
{
std::cout << d;
for (auto z : myWalkableEnum)
std::cout << z;
}
//outputs 70567
使用未定义的宏包装器声明一个列表,然后在各种情况下以不同的方式定义包装器的技巧,除了这个应用程序之外,还有许多应用程序。
在评论中已经有关于std::initializer_list (c++ 11)的讨论。 我提到example是为了遍历枚举。
或者std::initializer_list和一个更简单的语法:
enum E {
E1 = 4,
E2 = 8,
// ..
En
};
constexpr std::initializer_list<E> all_E = {E1, E2, /*..*/ En};
然后
for (auto e : all_E) {
// Do job with e
}
参考链接
枚举就不行。也许枚举不是最适合您的情况。
一个常见的约定是将最后一个枚举值命名为MAX,并使用它来控制一个int类型的循环。
对于MS编译器:
#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);
}
注意:这比简单的模板化自定义迭代器答案要少得多。
你可以通过使用typeof而不是decltype来让它与GCC一起工作,但我现在没有那个编译器来确保它能编译。