Как я могу переключить класс enum? - PullRequest
0 голосов
/ 25 апреля 2020

Предполагается, что перечислимые классы являются сильными перечислениями в том смысле, что они неявно не преобразуются в int. Например:

enum class EC { a, b };

Однако при переключении такого «сильного перечисления»:

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

g cc -Wreturn-type - хочет добавить предложение default к переключателю, даже если охвачены все допустимые значения перечисления:

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

В старом (не классовом) перечислении это имеет смысл, поскольку любой int мог быть случайно преобразован в EC. Но я (очевидно, ошибочно) предположил, что присвоение недопустимого члена перечисления классу перечисления было UB.

Как я могу использовать действительно сильные классы перечисления, когда компилятор понимает, что такие функции, как sw охватывают все возможные пути? Конечно, я мог бы просто добавить ветку default:, которая, как я знаю, никогда не сработает, но я хочу убедиться, что добавление большего числа членов к EC в будущем вызовет предупреждение переключатель .

Ответы [ 5 ]

1 голос
/ 25 апреля 2020

Вы можете вернуть фиктивную переменную, чтобы удалить «контроль достигает конца не пустой функции». Таким образом, предупреждение удаляется, и любые добавления в перечислимый класс все равно будут вызывать предупреждение в операторе switch:

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

  return 0; //dummy variable
}
1 голос
/ 25 апреля 2020

«управление достигает конца не пустой функции» весьма отличается от обычного «значения перечисления» c ', которое не обрабатывается в переключателе [-Wswitch] ". Я думаю, что компилятор здесь слишком осторожен, но это предупреждение может оказаться полезным, потому что оно предотвратит потенциальный UB в будущем, вызванный изменением enum и игнорированием предупреждения -Wswitch.

Переписав этот фрагмент, вы получите код для будущего:

онлайн-компилятор

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 голосов
/ 25 апреля 2020

В GCC / Clang / I CC вы можете отключить это предупреждение с помощью __builtin_unreachable():

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

    assert(false);
    __builtin_unreachable();
}

В MSV C __assume(0) можно использовать.

0 голосов
/ 25 апреля 2020

Это сработало для меня:

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;
}
0 голосов
/ 25 апреля 2020
Переменная

A enum - как в старой школе, так и в enum class могут храниться значения, которые не являются членами перечисления. Пока целочисленное значение вписывается в базовый тип (с некоторыми дополнительными ограничениями), его можно хранить в типе перечисления.

...