Selecting a valid random enum value in a general way

柔情痞子 提交于 2020-01-01 10:45:24

问题


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:

  1. Value range may not start from 0
  2. Value range may not end at std::numeric_limits::max()
  3. 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 Incrementing where successive variables are initialised by an incrementing static member 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 Incrementing values (which need an operator Underlying() const member).

    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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!