问题
Let's say we have an enumerated type E.
enum class E : underlying_type_of_E {
v1 = uE1,
v2 = uE2,
//...
vN = uEN
};
typedef typename std::underlying_type<E>::type uE;
In general, not all values of uE are valid values of E, because we can choose the relationship between them. Is there a general way of creating random, valid (named in definition, not assignable), values of E?
This, for example would not work:
std::mt19937 m;
std::uniform_int_distribution<uE> randomUE(0, std::numeric_limits<uE>::max());
E e = static_cast<E>( randomUE(m) );
because:
- Value range may not start from 0
- Value range may not end at std::numeric_limits::max()
- Value range may not be a range at all - we can select discrete values for E from uE, for example {1, 3, 64, 272}.
Given that all of the enumerated values are known at compile-time, I cannot imagine a reason why would this be in any way dangerous, or error-prone.
As for a context of why I want such a thing - I'm working on a genetic algorithm that uses templated gene storage. For now, I use enums as chromosomes and store them in std::vector<bool> which is converted into std::vector<enumT> on demand. The problem with this approach is mutation that flips random bits with given probability. That can cause problems, as it can produce invalid chromosomes that are unnamed enum values.
回答1:
You can do this if you're prepared to use a preprocessor macro to create both the enum type and some meta-data about it, but it's a minor hassle:
Invoke a variadic macro:
ENUM(E, v1 = uE1, v2 = uE2, // ... vN = uEN);Create a templated class
Incrementingwhere successive variables are initialised by an incrementingstaticmember by default, but can be assigned to from whatever your underlying type is (e.g.int).static Incrementing<E, Underlying> __VA_ARGS__; \Use the values above to initialise a array with the
Incrementingvalues (which need anoperator Underlying() constmember).static const Underlying values[] = { __VA_ARGS__ }; \
The values[] array then contains the named enumeration values....
There's a total overkill version of this concept I wrote years ago here, but I'd recommend just starting from scratch given your simple requirements.
来源:https://stackoverflow.com/questions/25357545/selecting-a-valid-random-enum-value-in-a-general-way