枚举 C++ 中的枚举
在 C++ 中,是否可以枚举枚举(运行时或编译时(首选))并为每次迭代调用函数/生成代码?
示例用例:
enum abc
{
start
a,
b,
c,
end
}
for each (__enum__member__ in abc)
{
function_call(__enum__member__);
}
看似重复的内容:
In C++, Is it possible to enumerate over an enum (either runtime or compile time (preferred)) and call functions/generate code for each iteration?
Sample use case:
enum abc
{
start
a,
b,
c,
end
}
for each (__enum__member__ in abc)
{
function_call(__enum__member__);
}
Plausible duplicates:
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
要添加到 StackedCrooked 的答案,您可以重载
operator++
、operator--
和operator*
并具有类似迭代器的功能。让我们用一些
template:现在,
Color
是一个常量双向迭代器。这是我在上面手动执行时编写的可重用类。我注意到它可以适用于更多的枚举,因此再次重复相同的代码是相当乏味的。下面是一个实现。
To add to StackedCrooked's answer, you can overload
operator++
,operator--
andoperator*
and have iterator-like functionality.Let's test with some
<algorithm>
template:Now,
Color
is a constant bidirectional iterator. Here is a reusable class I coded while doing it manually above. I noticed it could work for many more enums, so repeating the same code all over again is quite tedious.An implementation follows.
C++ 目前不提供枚举器迭代。尽管如此,有时还是会出现这种需要。常见的解决方法是添加标记开始和结束的值。例如:
C++ currently does not provide enumerator iteration. Despite that, the need sometimes arises for this. A common workaround is to add values that mark the beginning and the ending. For example:
如果没有一点体力劳动,这两者都是不可能的。如果您愿意深入研究该领域,很多工作都可以通过宏来完成。
Neither is possible without a little manual labour. A lot of the work can be done by macros, if you’re willing to delve into that area.
扩展一下Konrad所说的,这种情况下可能的一种习语“为每次迭代生成代码”的方法是使用包含文件来表示枚举:
File mystuff.h
enum.h:
File main.cpp
因此,要添加一个新元素“qux”,将其添加到文件 mystuff.h 中并编写
do_qux
函数。您不必触摸调度代码。当然,如果枚举中的值需要是特定的非连续整数,那么您最终会分别维护枚举定义和
ENUM_ELEMENT(foo)
... 列表,这很混乱。Expanding on what Konrad says, one possible idiom in the case of "generate code for each iteration" is to use an included file to represent the enumeration:
File mystuff.h
enum.h:
File main.cpp
So, to add a new element "qux", you add it to file mystuff.h and write the
do_qux
function. You don't have to touch the dispatch code.Of course if the values in your enum need to be specific non-consecutive integers, then you end up maintaining the enum definition and the
ENUM_ELEMENT(foo)
... list separately, which is messy.否
但是,您可以定义自己的类,通过迭代实现类似枚举的功能。您可能还记得 Java 1.5 之前的一个技巧,称为“类型安全枚举设计模式”。您可以执行 C++ 等效操作。
No
However, you could define your own class that implements enum-like features with iterations. You may recall a trick from the pre 1.5 Java days, called the "type safe enum design pattern". You could do the C++ equivalent.
我通常这样做:
range
是完全通用的,定义如下:I usually do that like this:
range
is completely generic, and defined like follows:这对我来说似乎很老套,但它可能适合您的目的:
如果您需要特殊的起始值,您可以将其设为常量并将其设置在枚举中。我没有检查它是否可以编译,但它应该接近那里:-)。
我认为这种方法对于您的用例来说可能是一个很好的平衡。如果您不需要对一堆不同的枚举类型执行此操作并且您不想处理预处理器的内容,请使用它。只要确保您评论并可能添加一个 TODO 以便稍后将其更改为更好的东西:-)。
This seems hacky to me, but it may suit your purposes:
If you need a special start value, you can make that a constant and set it in your enum. I didn't check if this compiles, but it should be close to being there :-).
I think this approach might be a good balance for your use case. Use it if you don't need to do this for a bunch of different enumerated types and you don't want to deal with preprocessor stuff. Just make sure you comment and probably add a TODO to change it at a later date to something better :-).
您可以使用 TMP 静态执行一些建议的运行时技术。
该程序的输出为:
请参阅 Abrahams、Gurtovoy 的“C++ 模板元编程”的第 1 章,了解对此技术的良好处理。与建议的运行时技术相比,这样做的优点是,当您优化此代码时,它可以内联静态数据,大致相当于:
内联
function_call
以获得编译器的更多帮助。对其他枚举迭代技术的同样的批评也适用于此。仅当您的枚举从头到尾连续递增时,此技术才有效。
You can perform some of the proposed runtime techniques statically with TMP.
The output from this program is:
See Chapter 1 of Abrahams, Gurtovoy "C++ Template Metaprogramming" for a good treatment of this technique. The advantage to doing it this way over the proposed runtime techniques is that, when you optimize this code, it can inline the statics and is roughly equivalent to:
Inline
function_call
for even more help from the compiler.The same criticisms of other enumeration iteration techniques apply here. This technique only works if your enumeration increments continuously from a through end by ones.
我喜欢模板,但我会记下这一点以供我将来/其他人使用,这样我们就不会迷失于上述任何内容。
为了以已知的有序方式比较事物,枚举很方便。为了提高整数值的可读性,它们通常被硬编码到函数中。有点类似于预处理器定义,不同之处在于它们不被文字替换,而是在运行时保留和访问。
如果我们有一个定义 HTML 错误代码的枚举,并且我们知道 500 秒内的错误代码是服务器错误,那么阅读以下内容可能会更好:
关键
部分是这样的,它们与数组类似!但它们用于转换整数值。
简短示例:
通常,枚举还与 char* 数组或字符串数组一起使用,以便您可以打印一些带有关联值的消息。通常它们只是枚举中具有相同值集的数组,如下所示:
当然,创建一个处理枚举迭代的通用类(如上面的答案)会更好。
I love templating, but I'm going to make note of this for my future/other peoples' usage, so we're not lost with any of the above.
Enums are convenient for the sake of comparing things in a known ordered fashion. They are typically used hard coded into functions for the sake of readability against integer values. Somewhat similar to preprocessor definitions, with the exception that they are not replaced with literals, but they are kept and accessed at runtime.
If we had an enum defining HTML error codes and we knew that error codes in the 500s are server errors, it might be nicer to read something like:
than
The key part is this, they are similar to arrays! But they are used to cast integer values.
Short example:
Oftentimes, enums are also used with char* arrays or string arrays so that you could print some message with the associated value. Normally they're just arrays with the same set of values in the enum, like so:
And of course it's even nicer to create a generic class which handles iteration for enums like the answers above.