Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic way to cast int to enum in C++

Tags:

c++

enums

casting

Is there a generic way to cast int to enum in C++?

If int falls in range of an enum it should return an enum value, otherwise throw an exception. Is there a way to write it generically? More than one enum type should be supported.

Background: I have an external enum type and no control over the source code. I'd like to store this value in a database and retrieve it.

like image 609
Leonid Avatar asked Nov 12 '10 14:11

Leonid


2 Answers

The obvious thing is to annotate your enum:

// generic code #include <algorithm>  template <typename T> struct enum_traits {};  template<typename T, size_t N> T *endof(T (&ra)[N]) {     return ra + N; }  template<typename T, typename ValType> T check(ValType v) {     typedef enum_traits<T> traits;     const T *first = traits::enumerators;     const T *last = endof(traits::enumerators);     if (traits::sorted) { // probably premature optimization         if (std::binary_search(first, last, v)) return T(v);     } else if (std::find(first, last, v) != last) {         return T(v);     }     throw "exception"; }  // "enhanced" definition of enum enum e {     x = 1,     y = 4,     z = 10, };  template<> struct enum_traits<e> {     static const e enumerators[];     static const bool sorted = true; }; // must appear in only one TU, // so if the above is in a header then it will need the array size const e enum_traits<e>::enumerators[] = {x, y, z};  // usage int main() {     e good = check<e>(1);     e bad = check<e>(2); } 

You need the array to be kept up to date with e, which is a nuisance if you're not the author of e. As Sjoerd says, it can probably be automated with any decent build system.

In any case, you're up against 7.2/6:

For an enumeration where emin is the smallest enumerator and emax is the largest, the values of the enumeration are the values of the underlying type in the range bmin to bmax, where bmin and bmax are, respectively, the smallest and largest values of the smallest bit-field that can store emin and emax. It is possible to define an enumeration that has values not defined by any of its enumerators.

So if you aren't the author of e, you may or may not have a guarantee that valid values of e actually appear in its definition.

like image 175
Steve Jessop Avatar answered Sep 27 '22 18:09

Steve Jessop


Ugly.

enum MyEnum { one = 1, two = 2 };  MyEnum to_enum(int n) {   switch( n )   {     case 1 :  return one;     case 2 : return two;   }   throw something(); } 

Now for the real question. Why do you need this? The code is ugly, not easy to write (*?) and not easy to maintain, and not easy to incorporate in to your code. The code it telling you that it's wrong. Why fight it?

EDIT:

Alternatively, given that enums are integral types in C++:

enum my_enum_val = static_cast<MyEnum>(my_int_val); 

but this is even uglier that above, much more prone to errors, and it won't throw as you desire.

like image 35
John Dibling Avatar answered Sep 27 '22 18:09

John Dibling