Given a C++11 enum class, is there some templating or other construct to iterate, at compile-time, over the set of all enumerators? Could one define a template to e.g. initialize an array with all possible values of that enum type?
Asked
Active
Viewed 268 times
0
-
You can roll your own enum-like type with a varadic template class and parameter packs starting with `template
class Enum`, but it isn't terribly pretty. C++ needs better reflection and there is a working group trying to tackle this. – Andrew Tomazos Jun 19 '13 at 16:00
2 Answers
3
One alternative technique is to resort to the pre-processor.
#define ITERATE_MY_ENUM(_) \
_(A,) \
_(B, =3) \
_(C,) \
_(D, =10)
enum MyEnum {
#define DEFINE_ENUM_VALUE(key, value) key value,
ITERATE_MY_ENUM(DEFINE_ENUM_VALUE)
#undef DEFINE_ENUM_VALUE
};
void foo() {
MyEnum arr[] = {
#define IN_ARRAY_VALUE(key, value) key,
ITERATE_MY_ENUM(IN_ARRAY_VALUE)
#udnef IN_ARRAY_VALUE
};
}
Some may consider it ugly, but it still keeps the code DRY.

zah
- 5,314
- 1
- 34
- 31
-
I had thought about using the preprocessor for this, but my approach would have been a lot more involved, using a number of boost macros. Your solution looks both a lot easier to read and a lot more lightweight. It should be possible to modify the code in such a way that `value` includes the `=`, so that you can leave value empty if you want auto-increment behaviour for some keys. The array should then be specified in terms of keys, obviously. Do you want to edit your code? – MvG Jun 20 '13 at 14:42
1
No, there is no such thing. Also note that the enum type can hold not just the values of the enumerators legally, but any combinations of them OR-ed together (vaguely speaking).
You probably could solve the problem using some simple code generator.
Reflecting comment: Here is a good summary of changes in C++11 regarding class enum. Those addressed implicit conversions, control over underlying type, name scoping, but no change of the fundamental nature. Enumerators are still just things close to literals with no discoverable connections. What you ask for would require kind of reflections, AFAIK it's not yet on the horizon.

Balog Pal
- 16,195
- 2
- 23
- 37
-
1I am not sure that the OR part of the answer is correct. As a matter of fact I am quite sure it is the other way around. An object of the enumeration type can only hold one of the enumerators, holding anything else is undefined behavior. The code `enum E { ONE=1, TWO=2 }; E e = ONE | TWO; switch (e) { case ONE: cout << "1"; break; case TWO: cout << "2"; break; default: cout << "other"; };` might not print anything at all (i.e. the compiler is allowed to optimize away the 'default' branch since all of the valid values of 'e' have their own case. – David Rodríguez - dribeas Jun 19 '13 at 15:40
-
-
I know that this oring together of values is valid for old `enum` enumerators, but had quietly hoped that `enum class` might get rid of that. In any case, listing all explicitely named enumerators would be fine. Just counting enumerators would be fine: as long as noone assigns explicit values, one could use casts to turn instances of the underlying type into valid values. – MvG Jun 19 '13 at 15:44
-
I'm not sure how one could even give the value `3` to a C++11 class enum containing values `1` and `2`. – juanchopanza Jun 19 '13 at 15:51
-
The generator I use (which I wrote myself) will _not_ generate iterators if any of the enum constants has an explicit value (an `=` immediately after the name). Similarly, it won't generate the `&` and `|` functions unless all have explicit values. – James Kanze Jun 19 '13 at 15:52
-
@MvG Why should `enum class` behave differently here. `enum` has always served two different, unrelated uses, and (as far as I know) continues to do so. – James Kanze Jun 19 '13 at 15:57
-
@BalogPal: +1, it's taken me a while to process the wording in the standard to make sure it is guaranteed – David Rodríguez - dribeas Jun 19 '13 at 16:48
-
For `enum E { ONE=1, TWO=2 }` you get 3 by `ONE | TWO`. The bitwise operators support using an enum as a bitmask. The type of the expression and operands (all three) are `E`. The rules about the four different flavours (scoped/unscoped, fixed/non-fixed) of enums are specified in 7.2 Enumeration declarations [dcl.enum] of the C++ standard. – Andrew Tomazos Jun 19 '13 at 18:04
-
@user1131467 you forgot a step: `static_cast
(ONE|TWO)`. – Yakk - Adam Nevraumont Jun 20 '13 at 00:26 -
@Yakk: That's odd, unscoped enum operands are subject to integral promotion with the bitwise operators like they are with all the arithmetic operators, I thought that the type of `ONE|TWO` was `E` - but this appears to be fantasy, it is actually `int` just the same as `ONE + TWO` or `ONE * TWO`. – Andrew Tomazos Jun 20 '13 at 00:40