C++11
scoped enums are great, you should use them whenever possible.
However, sometimes you need to convert an integer to a scoped enum value (say if you are getting it from user input).
Is there a safe way to do this and detect when the value is not valid (i.e., outside the permitted values of the enum)?
I believe just using static_cast leads to undefined behavior if the integer is not valid. Is there a generic way of doing that does not require writing a conversion function for each scoped enum type by hand (and that needs to be updated every time you add a new value to the enum)?
A common way to do that is to include in your enum an ending marker
enum class Colors : char
{
Red,
Green,
Blue,
Last_Element
}
Using this approach, when converting, you can check if the value you're using is less than the value of Last_Element.
Consider the following function:
template<typename T>
typename std::enable_if<std::is_enum<T>::value, bool>::type
IsValidEnumIntegral<T>(int integral)
{
return (int)(T::Last_Element) > integral;
}
and you could use it like so:
if(IsValidEnumIntegral<Colors>(2))
//do whatever
This would work for any enum you made with an element called Last_Element. You could go further to create a similar function to then auto-convert for you.
Note: This is not tested. I am not in a position to do so at the moment but I think this could work.
EDIT: This will only work if the enum in question uses a set of integers with no gaps for its elements. The function provided will also assume the enum does not contain negative integers, though a First_Element can easily be added to it.
[dcl.enum]/8:
For an enumeration whose underlying type is fixed, the values of the enumeration are the values of the underlying type.
This includes all scoped enumerations, because the underlying type of a scoped enum defaults to int
:
The underlying type can be explicitly specified using an enum-base. For a scoped enumeration type, the underlying type is
int
if it is not explicitly specified. In both of these cases, the underlying type is said to be fixed.
Thus, by verifying that the input value is within the range of the underlying type of the enum (which you can check with std::numeric_limits
and std::underlying_type
), you can be sure that the static_cast
will always have well-defined behavior.
However, that's not enough if the rest of your program isn't prepared to handle every value within the range of the enum's underlying type. In that case, you'll have to do validation yourself, possibly with something along the lines of @Altainia's answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With