GCC включить перечисление, сохранить отсутствующее предупреждение, но использовать по умолчанию
Используя GCC, если вы switch
по значению enum
, а в одном из перечислений отсутствует оператор case
, будет выдано предупреждение. Когда вы добавляете элемент default
, предупреждение больше не будет излучаться, что имеет смысл в общем случае.
Есть ли способ использовать оператор default
и по-прежнему иметь предупреждение, если не все значения enum
охвачены? Поскольку моя функция может иметь дело с нечистыми вводами, я хотел бы осветить общий случай, но все же получить предупреждения компилятора о том, что отсутствует список перечислений.
В настоящее время я заканчиваю назначение значения по умолчанию после оператора switch.
Ответы
Ответ 1
-Wswitch-enum, но к несчастью, поддерживает только последняя версия.
(Вы могли бы, конечно, имитировать поведение, которое вы хотите, используя goto вне коммутатора и опустив значение по умолчанию, но я бы настоятельно советовал ему, что он уродлив, а кто-то другой, читающий ваш код, будет иметь опыт WTF.)
Ответ 2
Прочитав ссылку от "David Rodríguez - dribeas", я подумал, что было бы полезно обобщить перечисленные здесь варианты.
Есть два способа сделать это: либо повернуть сообщения о отсутствующих случаях перечисления для всех операторов switch
, а затем отключить их для тех, которые вам не нужны, или оставить их по умолчанию и заставить ошибки для тех switch
заявлений, которые вы действительно заботитесь.
Вариант 1: Предупреждения для всех, отметьте некоторые как тихие
Во-первых, добавьте -Wswitch-enum
к вашим флагам компилятора, так что все инструкции switch
, даже те, у которых есть предложение default
, будут генерироваться предупреждения, если переименование не обрабатывается.
Затем для тех операторов switch
, где вы хотите, чтобы случай default
заботился о вещах и не хотел видеть предупреждения, заверните оператор switch
следующим образом:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch-enum"
switch () {
...
}
#pragma GCC diagnostic pop
Это временно отключит флаг -Wswitch-enum
(скрывая предупреждения о недостающих случаях перечисления) только для этого оператора case.
Вариант 2: предупреждать только о том, чтобы сделать это
Поскольку поведение GCC по умолчанию заключается в том, чтобы скрыть предупреждения, когда существует предложение default
, для этого параметра флаги компилятора не нужно изменять.
Вместо этого для тех операторов switch
, которые содержат предложение default
, но вы все еще хотите видеть предупреждения о недостающих случаях перечисления, оберните switch
следующим образом:
#pragma GCC diagnostic push
#pragma GCC diagnostic warning "-Wswitch-enum"
switch () {
...
}
#pragma GCC diagnostic pop
Это временно включает флаг -Wswitch-enum
между строками push
и pop
, в результате чего сообщения о отсутствующих случаях перечисления отображаются даже при наличии предложения default
. Вы можете изменить слово warning
на error
, если вы хотите, чтобы компиляция завершилась с ошибкой.
Ответ 3
К сожалению, на сегодняшний день ни gcc, ни llvm не могут обнаружить, что вы не сравниваете все значения enum
в switch
, если вы включаете в себя переключатель default
.
Ответ 4
Я бы сказал, что проблема больше на уровне enum
.
Что я имею в виду, так это то, что вы должны сначала подтвердить свой ввод (т.е. убедиться, что он действительно отображается в реальное перечисление) и только после проверки, следует использовать перечисление, и в этом случае значение по умолчанию становится избыточным.
Чтобы проверить ввод, простым решением, которое я использую, является создание перечисления через макрос, который также автоматически генерирует функции преобразования: от/до string
, от int
(или что-то еще).
Например:
DEFINE_ENUM_DETAILED(SomeEnum, int, (Foo, 0, "Foo")(Bar, 1, "Bar"));
Может генерировать:
struct SomeEnum {
enum { Foo = 0, Bar = 1 } type;
type FromString(std::string const& s) {
if (s == "Foo") { return Foo; }
if (s == "Bar") { return Bar; }
assert(0 && "SomeEnum::FromString - unknown value");
}
std::string ToString(type e) {
switch(e) {
case Foo: return "Foo";
case Bar: return "Bar";
}
}
type FromIntegral(int i) {
switch(i) {
case Foo: return Foo;
case Bar: return Bar;
}
assert(0 && "SomeEnum::FromIntegral- unknown value");
}
};
Это единственный способ, который я нашел, чтобы сгенерировать это легко (хотя преобразование строк здесь немного упрощено).
Другим решением будет использование script для генерации исходного кода из альтернативного файла.
РЕДАКТИРОВАТЬ: Операция и проверка коммутатора
Простой ответ (например, я сделал выше), чтобы программа выходила из коммутатора вместо использования предложения по умолчанию. Это возможно, если нормальный поток (при попадании в case
) не выйдет из переключателя.
switch(event) {
case Foo: {
// bla
return 0;
}
case Bar: {
return 0;
}
}
unreachable("should never have got there");
Ответ 5
Одна из причин заключается в том, что вы должны иметь возможность писать код без предупреждения, не нарушая вас. Если, например, у вас есть перечисление со 100 константами, вам нужно будет перечислить каждый из них в каждом операторе switch, даже если вам нужно только осмотреть несколько из них, если предупреждение должно работать так, как вы предложили.