我只是注意到不能在枚举上使用标准数学运算符,如++或+=。
那么,在c++枚举中遍历所有值的最佳方法是什么?
我只是注意到不能在枚举上使用标准数学运算符,如++或+=。
那么,在c++枚举中遍历所有值的最佳方法是什么?
当前回答
对于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一起工作,但我现在没有那个编译器来确保它能编译。
其他回答
将变量强制转换为int&类型可以在保持类型可读的同时进行递增。
#include <iostream>
enum MyEnum
{
ONE,
TWO,
THREE,
FOUR,
};
int main()
{
for (MyEnum v = MyEnum::ONE; v <= MyEnum::FOUR; ++(int&)v)
{
std::cout<<v<<std::endl;
}
return 0;
}
0
1
2
3
如果你不喜欢用最终的COUNT项污染你的枚举(因为如果你也在开关中使用枚举,那么编译器会警告你缺少大小写COUNT:),你可以这样做:
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);
}
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);
}
constexpr std::array甚至可以迭代非顺序的枚举,而无需编译器实例化数组。这取决于编译器的优化启发式以及是否取数组的地址。
In my experiments, I found that g++ 9.1 with -O3 will optimize away the above array if there are 2 non-sequential values or quite a few sequential values (I tested up to 6). But it only does this if you have an if statement. (I tried a statement that compared an integer value greater than all the elements in a sequential array and it inlined the iteration despite none being excluded, but when I left out the if statement, the values were put in memory.) It also inlined 5 values from a non-sequential enum in [one case|https://godbolt.org/z/XuGtoc]. I suspect this odd behavior is due to deep heuristics having to do with caches and branch prediction.
这里有一个godbolt的简单测试迭代的链接,演示了数组并不总是被实例化。
这种技术的代价是写入enum元素两次,并保持两个列表同步。
在Bjarne Stroustrup的c++编程语言书中,你可以读到他建议为特定的枚举重载操作符++。枚举是用户定义的类型,语言中存在针对这些特定情况的重载运算符。
你将能够编写以下代码:
#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;
}
测试代码:http://cpp.sh/357gb
注意,我使用的是枚举类。Code也可以很好地使用enum。但我更喜欢枚举类,因为它们是强类型的,可以防止我们在编译时犯错误。
c++没有自省,所以你不能在运行时确定这类事情。