12

I would like to know if there is any clever trick how to safely convert integer into enum. Before you vote that this is duplicate, I'm not asking about how to convert (int i; Enum e = static_cast<Enum>(i) is easy). I'm asking how to do it safely, verifying that resulting value really is in the enum.

Following code

enum class E {
    A = 1,
    B = 2
};

int main(int, char **) {
    int i = 3;
    E e = static_cast<E>(i);
}

will compile (AFAIK) but e will not contain valid value from the enum. Best way I came up with is something like

switch (i) {
    case 1:
        return E::A;
    case 2:
        return E::B;
    default:
        throw invalid_argument("");
}

which 1) doesn't look very smart 2) doesn't scale so well. I could probably put together some macros to make this easier but it still looks dumb.

So is there any "standard" way to do it?

halfer
  • 19,824
  • 17
  • 99
  • 186
graywolf
  • 7,092
  • 7
  • 53
  • 77
  • Maybe [this answer](http://stackoverflow.com/a/14589519/1106415) helps? (using a class enum makes sure that only specified values are allowed, AFAIK) – hlt Jul 28 '15 at 13:07
  • 2
    Unless you have some way to get the enum size (e.g. `enum class E{A=0, B, ENUM_COUNT};`, where `ENUM_COUNT` will give `2`, and the enums are positive and increasing from 0, then the answer is no. Enums are very primitive. See the many other questions on SO about overcoming these issues. Some Macro based approaches are good, and I can't help but plug my own question [here](http://stackoverflow.com/questions/31466701/searchable-enum-like-object-with-string-and-int-conversion) that has some useful answers and suggestions that could help you. – AndyG Jul 28 '15 at 13:10
  • @hlt that seems like other way that I need – graywolf Jul 28 '15 at 13:25
  • @AndyG I read your question and it seems really interesting. But my use-case is a bit performance sensitive and I can't help myself but think (ok, didn't do benchmarks) that `switch(int i)` must be faster than `std::find_if` in your function for int->enum conversion.. – graywolf Jul 28 '15 at 13:28
  • 1
    don't think you can do it.. C++ programs are not built to be "awared" of their contents, only preform blind code – David Haim Jul 28 '15 at 13:41
  • @Paladin: If you read the answers posted to that question, they provide switch statements and all the other stuff you require. – AndyG Jul 28 '15 at 13:54
  • 1
    How you verify a value also depends on the intended use of the enums. Technically, `A | B` is a valid value for your enum (but maybe not for the application). – Bo Persson Jul 28 '15 at 13:56
  • @BoPersson: Meh, that's debateable. – Lightness Races in Orbit Jul 28 '15 at 15:18
  • 1
    _"I'm asking how to do it safely, verifying that resulting value really is in the enum."_ You are using a personal definition of "safely" which the C++ standard and compilers do not agree with. There is nothing "unsafe" about a value of an enumeration type that does not correspond to one of the enumerators of that type. Given `enum E { max=255 };` then `E{1}` is a valid value, and perfectly "safe". If you want a type that can only take on specific values then you should not be using an enumeration type. – Jonathan Wakely Jul 28 '15 at 15:35
  • Are you willing to use a macro to declare the enum? If so, there are ways to generate a safe conversion function from int. – antron Jul 28 '15 at 16:23

1 Answers1

8

If you do not have to convert the numeric value as well, I'd suggest something like

switch (i)
{
    case static_cast<int>(E::A):
    case static_cast<int>(E::B):
        return static_cast<E>(i);
    default:
        throw invalid_argument("");
}

At least that prevents some common mistakes like forgetting to change either the case or the return value or simply looking up the wrong numeric value. Also it's much more refactoring friendly (think about changing the numeric value - after all you define an enum so that you don't have to change the value in more than one place).

Unfortunately that still isn't very nice, but its the best way I know. Well, unless you want to use X macros.

Paul Groke
  • 6,259
  • 2
  • 31
  • 32