samedi 2 décembre 2017

Safely compare integer to strongly typed enum

How can one safely compare an integral value, of unknown type, to a strongly typed enum, when it's possible that the integral value may not be within the range of enumeration values?

The most obvious way to compare an integral value to an enum would be to cast the value to the enum type, E, and compare to the enumeration value, E::A, like this:

template <typename I, typename E>
bool compare(I a, E b) { return static_cast<E>(a) == b; }

However, if a is not in the range of enumeration values, this leads to undefined behavior, per [expr.static.cast]/10:

A value of integral or enumeration type can be explicitly converted to an enumeration type. The value is unchanged if the original value is within the range of the enumeration values (7.2). Otherwise, the resulting value is unspecified (and might not be in that range).

This can be seen in the resulting failure (compare as above):

enum E : uint8_t { A = 0 };
compare(256, E::A); // returns true, 256 == E::A, but E::A = 0

One could instead cast the enum to the integral type, but this can lead to incorrect results if the integral type can not represent all the enum values:

enum E : int { A = 256 };
template <typename I, typename E>
bool compare(I a, E b) { return a == static_cast<I>(b); }
compare((uint8_t)0); // returns true, 0 == E::A, but E:A = 256

Aucun commentaire:

Enregistrer un commentaire