How do I switch over an enum class?

2.9k views Asked by At

Enum classes are supposed to be strong enums in the sense that they don't implicitly convert to and from int. For instance:

enum class EC { a, b };

However, when switching over such a "strong enum":

int sw(EC ec) {
  switch (ec) {
    case EC::a: return 0;
    case EC::b: return 1;
  }
}

gcc -Wreturn-type-wants me to add a default clause to the switch even though all legal enum values are covered:

warning: control reaches end of non-void function [-Wreturn-type]

In an old (non-class) enum, this makes sense, because any int could have been accidentally converted to EC. But I had (apparently wrongly) assumed that assigning an invalid enum member to an enum class was UB.

How can I use truly strong enum classes where the compiler realises that functions like sw cover all possible paths? Of course I could just add a default: branch that I know will never be triggered, but I want to make sure that adding more members to EC in the future will trigger a warning in the switch.

5

There are 5 answers

5
Jesper Juhl On

A enum variable - both old-school one and enum class can hold values that are not one of the members of the enumeration. As long as the integer value fits within the underlying type (with a few more restrictions), it is valid to store it in the enumeration type.

4
Azam Bham On

You can return a dummy variable, to remove the "control reaches end of non-void function". This way, the warning is removed, and any additions to the enum-class will still trigger a warning in the switch statement:

int sw(EC ec) {
  switch (ec) {
    case EC::a: return 0;
    case EC::b: return 1;
  }

  return 0; //dummy variable
}
1
user7860670 On

"control reaches end of non-void function" is quite different from common "enumeration value 'c' not handled in switch [-Wswitch]" warning. I think compiler is being a bit too cautious here, but this warning may turn out to be handy because it will prevent potential future UB caused by modification of enum and ignoring of -Wswitch warning.

Rewriting this snippet like this would make code future proof:

online compiler

enum class EC { a, b /*,c */ };

int sw(EC ec) {
    int result{};
  switch (ec) { // warning: enumeration value 'c' not handled in switch [-Wswitch]
    case EC::a: result = 0; break;
    case EC::b: result = 1; break;
  }
  return result; // control flow will always leave function properly
}
0
mzimmers On

This worked for me:

enum class EC {a, b, c};
int sw (EC ec)
{
    int rc;
    switch (ec)
    {
        case EC::a:
        rc = 0;
        break;
    case EC::b:
        rc = 1;
        break;
    }
    return rc;
}
1
Evg On

In GCC/Clang/ICC you can silence this warning with __builtin_unreachable():

int sw(EC ec) {
    switch (ec) {
        case EC::a: return 0;
        case EC::b: return 1;
    }

    assert(false);
    __builtin_unreachable();
}

In MSVC __assume(0) can be used.