5

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.

tsuki
  • 907
  • 4
  • 17
  • Could you have a mapping from `0..N` to your enum ? – Jarod42 Aug 18 '14 at 07:14
  • Well, for MY enum - yes, but I'm asking for a general solution. Named enum values are known to the compiler so shouldn't C++ provide this information in some way? – tsuki Aug 18 '14 at 07:17
  • 1
    If you're asking if there is a language-supported way to "enumerate" an `enum` the answer is no, that isn't a feature of C++. There are [tricks you can use if the enum is sequential](http://stackoverflow.com/questions/1390703/enumerate-over-an-enum-in-c), but that isn't an option for you, so I don't see a general solution forthcoming. – WhozCraig Aug 18 '14 at 08:10
  • 1
    @tsuki It's not clear what you're asking for. If you consider arbitrary enums, then what does your random distribution mean in cases like `enum { one = 1, un = 1, eins = 1 };`? – James Kanze Aug 18 '14 at 08:36
  • @JamesKanze I didn't know you could do that with enums! Thanks! Your comment could be posted as an answer as it shows that this isn't possible. – tsuki Aug 18 '14 at 08:46
  • @tsuki re James' comment - whether it's still possible depends on your requirements: given say `enum E { one = 1, un = 1, two };` you could have a 50/50 chance of generating E(1)/E(2), or a 2/3rds / 1/3rd probability split, or as you say it might be that without being able to say exactly which identifier the enumeration represents you just want to trigger an error or find another approach to your problem.... – Tony Delroy Aug 19 '14 at 01:24

1 Answers1

2

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.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252