Ответ 1
В общем случае enum
не являются исключительными. Кто-то может назвать вашу функцию, например, useType( (type_t)3 );
. Это упоминается специально в С++ 14 [dcl.enum]/8:
Можно определить перечисление, которое имеет значения, не определенные каким-либо из его счетчиков.
Теперь существует множество правил о том, какие другие значения возможны для других типов перечислений.
Существует две категории перечисления. Первый - фиксированный базовый тип, например. enum type_t : int
или enum class type_t
. В этих случаях все значения базового типа являются допустимыми перечислениями.
Второй не является фиксированным базовым типом, который включает в себя pre-С++ 11 перечисления, такие как ваши. В этом случае правило о значениях можно суммировать, сказав: вычислить наименьшее количество бит, необходимое для хранения всех значений перечисления; то любое число, выражаемое в этом количестве битов, является допустимым значением.
Итак, в вашем конкретном случае один бит может содержать оба значения A
и B
, поэтому 3
недопустимое значение для счетчика.
Но если ваше перечисление было A,B,C
, то даже если 3
не указано конкретно, это правильное значение приведенным выше правилом. (Таким образом, мы видим, что почти все перечисления не будут эксклюзивными).
Теперь нам нужно посмотреть правило о том, что произойдет, если кто-то действительно попытается преобразовать 3
в type_t
. Правило преобразования - С++ 14 [expr.static.cast]/10, в котором говорится, что создается неопределенное значение.
Однако CWG issue 1766 признал, что текст С++ 14 был дефектным и заменил его следующим:
Значение интегрального или перечисляемого типа может быть явно преобразовано в полный тип перечисления. Значение не изменяется, если исходное значение находится в диапазоне значений перечисления (7.2). В противном случае поведение undefined.
Поэтому в вашем конкретном случае ровно два счетчика со значением 0
и 1
, никакое другое значение не возможно, если программа уже вызвала поведение undefined, поэтому предупреждение можно считать ложным положительным.
Чтобы удалить предупреждение, добавьте случай default:
, который что-то делает. Я также хотел бы предложить в интересах защитного программирования, что в любом случае неплохо иметь случай по умолчанию. На практике это может служить "сдерживанием" поведения undefined: если кто-то действительно имеет недопустимое значение, то вы можете просто выбросить или прервать его.
NB: Что касается самого предупреждения: невозможно, чтобы компилятор точно предупреждал, когда и только если поток управления достигнет конца функции, потому что это потребует решения проблемы с остановкой.
Они склонны ошибаться со стороны осторожности: компилятор будет предупреждать, если он не совсем уверен, что означает ложные срабатывания.
Таким образом, наличие этого предупреждения необязательно указывает на то, что исполняемый файл фактически разрешил вход в путь по умолчанию.