Должны ли операторы switch всегда содержать предложение по умолчанию?

255

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

  1. Есть ли разумная причина всегда включать оператор по умолчанию?

  2. Этот язык зависит? Я не помню, какой язык я использовал в то время - может быть, это относится к некоторым языкам, а не к другим?

tttppp
источник
9
Это будет зависеть от языка в значительной степени
скаффман

Ответы:

277

Переключатель дел должен почти всегда иметь defaultдело.

Причины использовать default

1. «поймать» неожиданное значение

switch(type)
{
    case 1:
        //something
    case 2:
        //something else
    default:
        // unknown type! based on the language,
        // there should probably be some error-handling
        // here, maybe an exception
}

2. Для обработки действий «по умолчанию», где случаи для особого поведения.

Вы видите это много в программах, управляемых меню и сценариях оболочки bash. Вы также можете увидеть это, когда переменная объявляется вне регистра, но не инициализируется, и каждый случай инициализирует ее чем-то другим. Здесь по умолчанию нужно также инициализировать его, чтобы код строки, обращающийся к переменной, не вызывал ошибку.

3. Чтобы показать, что кто-то читает ваш код, вы рассмотрели этот случай.

variable = (variable == "value") ? 1 : 2;
switch(variable)
{
    case 1:
        // something
    case 2:
        // something else
    default:
        // will NOT execute because of the line preceding the switch.
}

Это был упрощенный пример, но суть в том, что тот, кто читает код, не должен удивляться, почему variableне может быть что-то, кроме 1 или 2.


Единственный случай, о котором я могу подумать, чтобы НЕ использовать, defaultэто когда коммутатор проверяет что-то, где его довольно очевидная любая альтернатива может быть счастливо проигнорирована.

switch(keystroke)
{
    case 'w':
        // move up
    case 'a':
        // move left
    case 's':
        // move down
    case 'd':
        // move right
    // no default really required here
}
Vanwaril
источник
26
Ваш пример касательно нажатия клавиш противоречит остальному тому, что вы только что сказали. : | Я думаю, что более подробное объяснение будет иметь смысл, например: вам не нужно значение по умолчанию в этом случае, потому что, если нажата другая клавиша, вам все равно, но если переданная переменная отличается от ожидаемой, мы заботимся ,
Андрей
1
В то же время, если вы проверяете параметр GET, вам может не потребоваться генерировать исключение каждый раз, когда пользователь изменяет URL-адрес получения на недопустимый: [
Andrew
4
@Andrew WASD - обычное явление для движений персонажей компьютерных игр. Вам не потребуется никаких действий по умолчанию, так как другие взаимодействия могут быть назначены другим клавишам. В этом типе переключателя хорошо вызывать функции движения.
Джемилойи
13
Некоторые компиляторы предупреждают при включении перечисления, если регистр пропущен, и добавление регистра по умолчанию будет подавлять это предупреждение. Учитывая, что, по моему опыту, это очень распространенный источник ошибок (забыв обновить ключ где-то после добавления значения enum), это очень хорошая причина, чтобы пропустить регистр по умолчанию.
RDB
3
@virusrocks Если ваше условие - перечисление, у вас все еще могут быть неожиданные значения. Например, если вы добавите новое значение в перечисление и забудете обновить параметр. Кроме того, в некоторых языках вы можете назначать целочисленные значения для перечислений. В C ++ enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;делает допустимый MyEnumэкземпляр, который не равен FOOили BAR. Если любая из этих проблем приведет к ошибке в вашем проекте, случай по умолчанию поможет вам найти ошибку очень быстро, часто без необходимости в отладчике!
cdgraham
54

Нет.

Что если нет действия по умолчанию, контекст имеет значение. Что делать, если вы хотите действовать только на нескольких ценностях?

Возьмите пример чтения нажатий клавиш для игры

switch(a)
{
   case 'w':
     // Move Up
     break;
   case 's':
     // Move Down
     break;
   case 'a':
     // Move Left
     break;
   case 'd':
     // Move Right
     break;
}

Добавление:

default: // Do nothing

Это просто трата времени и увеличивает сложность кода без причины.

Джаред Келлс
источник
14
Хороший пример. Но на самом деле, добавление предложения по умолчанию с простым // do nothingкомментарием проясняет, что это «хорошо», если не все случаи покрыты, в отличие от других операторов switch, где это было бы «не хорошо».
Гвоздь
8
Нет. Кодирование - это не только обработка некоторых случаев. Также это служит документом. Если написать default: и комментировать как // Ничего не делать или что-то еще, читаемость кода улучшается.
JongAm Park
22
Не согласен с другими комментариями. Добавление по умолчанию // Ничего не добавляет, добавляет очень мало, если вы не знаете, как работает код. Я могу посмотреть на оператор switch без значения по умолчанию и знать, что по умолчанию ничего не делается. Добавление беспорядка не делает это более очевидным.
Роберт Ноак
Именно. Это та же концепция передачи всех почтовых параметров. Вы обращаетесь с теми, о ком заботитесь, а не с другими.
Джимми Кейн
2
@jybrd Если вы не верите, что предыдущий разработчик преднамеренно пропустил настройки по умолчанию, почему вы поверите, что они были правы? Значение по умолчанию может быть случайно пустым, так же как и полностью отсутствующим. Комментарий не нужен для чего-то такого тривиального. Это беспорядок в коде. Напишите полное тестирование, чтобы показать свои намерения. (Просто мое мнение)
Роберт Ноак
45

НЕ иметь стандартный регистр может быть полезным в некоторых ситуациях.

Если ваши варианты переключения являются перечисляемыми значениями, не имея регистра по умолчанию, вы можете получить предупреждение компилятора, если пропустите какие-либо случаи. Таким образом, если новые значения enum будут добавлены в будущем, и вы забудете добавить регистры для этих значений в коммутаторе, вы сможете узнать о проблеме во время компиляции. Вы все равно должны убедиться, что код выполняет соответствующие действия для необработанных значений, в случае, если недопустимое значение было приведено к типу enum. Так что это может лучше всего подойти для простых случаев, когда вы можете вернуться в enum case, а не break.

enum SomeEnum
{
    ENUM_1,
    ENUM_2,
    // More ENUM values may be added in future
};

int foo(SomeEnum value)
{
    switch (value)
    {
    case ENUM_1:
        return 1;
    case ENUM_2:
        return 2;
    }
    // handle invalid values here
    return 0;
 }
Харлан Касслер
источник
Это важное наблюдение! Это применимо еще больше в Java, потому что не позволяет вам приводить целые числа к перечислениям.
Лий
2
В вашем примере вы можете выдать исключение вместо возврата после оператора switch. Таким образом, вы можете выполнить статическую проверку компилятором и получить явную ошибку в случае непредвиденной ситуации.
Лий
1
Я согласен. В Swift для каждого примера switch должен быть исчерпывающим, иначе вы получите ошибку компилятора! Предоставление значения по умолчанию просто заглушает эту полезную ошибку. С другой стороны, предоставление значения по умолчанию, если все случаи обрабатываются, на самом деле выдает предупреждение компилятора (недостижимый оператор).
Энди
1
Просто исправил ошибку, которая вызвала бы предупреждение от компилятора, если бы не было значения по умолчанию: так, как правило, переменные Switch over enum не должны иметь значений по умолчанию.
Нотан
42

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

Вещи могут и действительно пойти не так, как надо. Ценности будут не такими, как вы ожидаете, и так далее.

Отсутствие необходимости включать предложение по умолчанию означает, что вы уверены, что знаете набор возможных значений. Если вы считаете, что знаете набор возможных значений, то, если значение выходит за пределы этого набора возможных значений, вы хотите, чтобы об этом сообщили - это, безусловно, ошибка.

Вот почему вы всегда должны использовать предложение по умолчанию и выдавать ошибку, например, в Java:

switch (myVar) {
   case 1: ......; break;
   case 2: ......; break;
   default: throw new RuntimeException("unreachable");
}

Нет причин включать больше информации, чем просто «недостижимая» строка; если это действительно произойдет, вам все равно придется посмотреть на источник, значения переменных и т. д., и трассировка стека исключений будет включать этот номер строки, поэтому не нужно тратить свое время на запись большего количества текста в сообщение об исключении.

Адриан Смит
источник
39
Я бы предпочел, throw new RuntimeException("myVar invalid " + myVar);поскольку это может дать вам достаточно информации, чтобы выяснить и исправить ошибку без необходимости использовать отладчик и проверять переменные, что может быть трудно, если это редко встречающаяся проблема, которую сложно воспроизвести.
Крис Додд
1
Что если это не условие ошибки для значения, которое не соответствует ни одному из случаев?
Гейб
4
Если это не условие ошибки, тогда не будет необходимости default:. Но чаще всего этого не происходит, каждый оставляет значение по умолчанию, потому что думает, что myVarникогда не может иметь никакого значения, кроме перечисленных; однако я не могу сосчитать, сколько раз я был удивлен в реальной жизни, когда переменная имела значение, отличное от значений, которые она «могла бы» иметь. В этих случаях я был благодарен за исключение, заставляющее меня увидеть это сразу, а не вызывать какую-то другую ошибку позже (более трудную для отладки) или неправильный ответ (может быть пропущен при тестировании).
Эдриан Смит
2
Я согласен с Адрианом. Терпеть неудачу и терпеть неудачу рано.
Сладкий
Я предпочитаю бросать AssertionErrorвместо RuntimeException, так как эта ситуация очень похожа на утверждение о том, что myVarэто одно из обрабатываемых значений. Также меньше вероятность того, что кто-то поймает и проглотит ошибку.
Филипп Вендлер
15

В моей компании мы пишем программное обеспечение для рынка авионики и обороны, и мы всегда включаем оператор по умолчанию, потому что ВСЕ случаи в операторе switch должны явно обрабатываться (даже если это просто комментарий, говорящий «ничего не делать»). Мы не можем позволить программному обеспечению просто вести себя неправильно или просто зависать от неожиданных (или даже тех, которые мы считаем невозможными) значений.

Можно обсудить, что случай по умолчанию не всегда необходим, но, всегда требуя его, он легко проверяется нашими анализаторами кода.

Курт Паттын
источник
1
У меня такое же требование, где я работаю; мы пишем код для встроенных микроконтроллеров, которые должны проходить строгие проверки безопасности и часто подвергаются EMI. Было бы безответственно предполагать, что перечисляемая переменная никогда не будет иметь значения, которого нет в списке перечисления.
oosterwal
12

Должен ли оператор switch всегда включать предложение по умолчанию? Нет. Обычно включать в себя по умолчанию.

Включение предложения по умолчанию имеет смысл только в том случае, если для этого нужно что-то сделать, например утвердить условие ошибки или обеспечить поведение по умолчанию. Включение одного «только потому, что» является культовым программированием и не дает никакой ценности. Это эквивалент «переключателя», когда все операторы «если» должны включать «еще».

Вот тривиальный пример того, где это не имеет смысла:

void PrintSign(int i)
{
    switch (Math.Sign(i))
    {
    case 1:
        Console.Write("positive ");
        break;
    case -1:
        Console.Write("negative ");
        break;
    default: // useless
    }
    Console.Write("integer");
}

Это эквивалент:

void PrintSign(int i)
{
    int sgn = Math.Sign(i);
    if (sgn == 1)
        Console.Write("positive ");
    else if (sgn == -1)
        Console.Write("negative ");
    else // also useless
    {
    }
    Console.Write("integer");
}
Гейб
источник
Я не согласен. ИМХО, единственное время, когда по умолчанию не должно существовать, это если нет способа, на данный момент и навсегда, что набор входов может измениться, и вы охватили все возможные значения. Самым простым случаем, о котором я могу думать, является логическое значение из базы данных, где единственными ответами (до изменения SQL!) Являются истина, ложь и NULL. В любом другом случае наличие по умолчанию с утверждением или исключением «не должно случиться!» имеет смысл. Если ваш код изменяется, и у вас есть одно или несколько новых значений, вы можете убедиться, что код для них есть, и ваши тесты взорвутся, если вы этого не сделаете.
Харпер Шелби
4
@Harper: Ваш пример подпадает под категорию «заявить об ошибке».
Гейб
Я бы сказал, что мой пример является нормой, и что исключение составляет небольшое количество случаев, когда один может быть на 100% уверен, что каждый возможный случай покрыт и не требуется значение по умолчанию. Ваш ответ сформулирован так, что он звучит (по крайней мере, для меня) так, как будто невыполнение обязательств по умолчанию будет происходить чаще, чем нет.
Харпер Шелби
@ Харпер: Хорошо, я изменил формулировку, чтобы указать, что ситуация бездействия менее распространена.
Гейб
4
Я думаю, что default:в этих случаях кодифицирует ваши предположения. Например, это нормально, когда sgn==0печатать integer(ни положительный, ни отрицательный), или это ошибка? Для меня, читающего этот код, сложно сказать. Я бы предположил, что вы не хотите писать zeroв этом случае integer, и что программист сделал предположение, что sgnможет быть только -1 или +1. Если бы это было так, наличие этого параметра default:позволило бы программисту отлавливать допущенную ошибку заранее и изменять код.
Эдриан Смит
7

Насколько я вижу, ответ «по умолчанию» является необязательным, говорить, что переключатель должен всегда содержать значение по умолчанию, все равно, что говорить, что каждое if-elseif должно содержать «else». Если есть логика, которая должна быть сделана по умолчанию, тогда должен присутствовать оператор 'default', но в противном случае код мог бы продолжать выполняться, ничего не делая.

Гершон Херцег
источник
6

Оборонное программирование обычно имеет предложение по умолчанию, когда оно на самом деле не нужно. Это обычно приводит к слишком сложному коду из-за слишком большого количества кода обработки ошибок. Этот код обработки и обнаружения ошибок ухудшает читабельность кода, усложняет обслуживание и в конечном итоге приводит к большему количеству ошибок, чем решает.

Поэтому я считаю, что если по умолчанию не будет достигнуто - вам не нужно его добавлять.

Обратите внимание, что «не должно быть достигнуто» означает, что если оно достигнуто, то это ошибка в программном обеспечении - вам нужно проверить значения, которые могут содержать нежелательные значения из-за ввода пользователя и т. Д.

Офир Йоктан
источник
3
Еще одна распространенная причина получения неожиданных случаев: другие части кода изменены, возможно, спустя годы.
Хендрик Браммерманн
Действительно, это очень опасное поведение. По крайней мере, я бы добавил предложение assert (). Тогда это легко обнаруживается, когда есть ошибка.
Курт Паттин,
5

Я бы сказал, что это зависит от языка, но в C, если вы включаете тип enum и обрабатываете все возможные значения, вам, вероятно, лучше НЕ включать регистр по умолчанию. Таким образом, если позже вы добавите дополнительный тег enum и забудете добавить его в коммутатор, компетентный компилятор выдаст вам предупреждение о пропущенном регистре.

Крис Додд
источник
5
«Каждое возможное значение» вряд ли будет обрабатываться с помощью перечислений. Вы можете привести целое число к перечислению, даже если это конкретное значение не определено явно. А какой компилятор предупреждает о пропавшем случае?
TrueWill
1
@TrueWill: Да, вы можете использовать явные приведения для написания запутанного кода, который невозможно понять; чтобы написать понятный код, вам следует избегать этого. gcc -Wall(своего рода наименьший общий знаменатель компетентных компиляторов) выдает предупреждения о необработанных перечислениях в выражениях switch.
Крис Додд
4

Если вы знаете, что оператор switch будет иметь только строго определенный набор меток или значений, просто сделайте это для охвата баз, таким образом вы всегда получите правильный результат. Просто установите значение по умолчанию над меткой, которая будет программно / логически быть лучшим обработчиком для других значений.

switch(ResponseValue)
{
    default:
    case No:
        return false;
    case Yes;
        return true;
}
deegee
источник
Нужна ли здесь толстая кишка default? Или это позволяет использовать какой-то особый синтаксис, который позволял вам его опускать?
Ponkadoodle
Требуется двоеточие, это была опечатка, спасибо, что обратили на это мое внимание.
Диджи
3

По крайней мере, это не обязательно в Java. Согласно JLS, он говорит, что может присутствовать как минимум один случай по умолчанию. Это означает, что ни один случай по умолчанию не приемлем. Время от времени также зависит от контекста, который вы используете оператор switch. Например, в Java следующий блок переключателей не требует регистра по умолчанию

private static void switch1(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        break;
    case "Tuesday":
        System.out.println("Tuesday");
        break;
    }
}

Но в следующем методе, который ожидает вернуть строку, случай по умолчанию пригодится, чтобы избежать ошибок компиляции

    private static String switch2(String name) {
    switch (name) {
    case "Monday":
        System.out.println("Monday");
        return name;

    case "Tuesday":
        System.out.println("Tuesday");
        return name;

    default:
        return name;
    }
}

хотя вы можете избежать ошибки компиляции для вышеприведенного метода, не используя регистр по умолчанию, просто добавив оператор return в конце, но предоставив регистр по умолчанию, он станет более читабельным.

Шива Кумар
источник
3

Так говорят некоторые (устаревшие) руководства, такие как MISRA C :

Требование к заключительному предложению по умолчанию - защитное программирование. Этот пункт должен либо предпринять соответствующие действия, либо содержать соответствующий комментарий о том, почему никаких действий не предпринимается.

Этот совет устарел, потому что он не основан на соответствующих в настоящее время критериях. Явное упущение - то, что сказал Харлан Кэслер:

Если оставить регистр по умолчанию, компилятор может опционально предупредить или завершить работу при обнаружении необработанного регистра. Статическая верификация в конце концов лучше, чем любая динамическая проверка, и, следовательно, не является достойной жертвой, когда вам также нужна динамическая проверка.

Как также показал Харлан, функциональный эквивалент случая по умолчанию может быть воссоздан после переключения. Что тривиально, когда каждый случай является ранним возвращением.

Типичная потребность в динамической проверке - это обработка ввода в широком смысле. Если значение приходит из-за пределов контроля программы, ему нельзя доверять.

Это также тот случай, когда Мисра придерживается позиции крайне оборонительного программирования, поэтому, пока недопустимое значение является физически представимым, его нужно проверять, независимо от того, является ли программа корректной. Что имеет смысл, если программное обеспечение должно быть максимально надежным при наличии аппаратных ошибок. Но, как сказал Офир Йоктан, большинство программного обеспечения лучше не «обрабатывать» ошибки. Последняя практика иногда называется оскорбительным программированием .

user2394284
источник
2

У вас должно быть значение по умолчанию для перехвата ожидаемых значений.

Однако я не согласен с Адрианом Смитом, что ваше сообщение об ошибке по умолчанию должно быть совершенно бессмысленным. Может быть необработанный случай, который вы не предвидели (что-то вроде этого), что ваш пользователь в конечном итоге увидит, и сообщение типа «недоступный» совершенно бессмысленно и никому не поможет в этой ситуации.

Например, сколько раз у вас был совершенно бессмысленный BSOD? Или фатальное исключение @ 0x352FBB3C32342?

Джон Хант
источник
например, помните, что не только разработчик всегда видит сообщения об ошибках. Мы живем в реальном мире, люди делают ошибки.
Джон Хант
2

Если значение переключателя ( switch (переменная )) не может достичь значения по умолчанию, тогда значение по умолчанию вообще не требуется. Даже если мы сохраняем регистр по умолчанию, он вообще не выполняется. Это мертвый код.

Shiju
источник
2

Это необязательное кодирование «соглашение». В зависимости от использования, является ли это необходимо или нет. Я лично считаю, что если вам это не нужно, его не должно быть. Зачем включать что-то, что не будет использоваться или достигнуто пользователем?

Если возможности регистра ограничены (т. Е. Булево), то предложение по умолчанию является избыточным !

Дэнни Махони
источник
2

Если в switchоператоре нет случая по умолчанию , поведение может быть непредсказуемым, если этот случай возникает в какой-то момент времени, что не было предсказуемо на этапе разработки. Хорошей практикой является включение defaultдела.

switch ( x ){
  case 0 : { - - - -}
  case 1 : { - - - -}
}

/* What happens if case 2 arises and there is a pointer
* initialization to be made in the cases . In such a case ,
* we can end up with a NULL dereference */

Такая практика может привести к ошибке, такой как разыменование NULL , утечка памяти, а также к другим типам серьезных ошибок .

Например, мы предполагаем, что каждое условие инициализирует указатель. Но если defaultпредполагается возникновение кейса и если мы не инициализируем в этом случае, то есть все шансы получить исключение с нулевым указателем. Следовательно, предлагается использовать оператор defaultcase, хотя он может быть тривиальным.

Тревор
источник
2

Случай по умолчанию может не понадобиться в ключе, используемом enum. когда switch содержит все значения, регистр по умолчанию никогда не будет выполнен. Так что в этом случае это не обязательно.

iOkay
источник
1

Зависит от того, как работает переключатель на определенном языке, однако на большинстве языков, когда ни один регистр не соответствует, выполнение проваливается через оператор switch без предупреждения. Представьте, что вы ожидали некоторый набор значений и обрабатывали их в switch, однако вы получаете другое значение на входе. Ничего не происходит, и вы не знаете, ничего не случилось. Если вы поймали дело по умолчанию, вы бы знали, что что-то не так.

Габриэль Щербак
источник
1

Я не согласен с наиболее проголосовавшим ответом Ванварила выше.

Любой код добавляет сложности. Также тесты и документация должны быть сделаны для этого. Так что всегда хорошо, если вы можете программировать, используя меньше кода. Мое мнение таково, что я использую предложение по умолчанию для неисчерпывающих операторов переключения, в то время как я не использую предложение по умолчанию для исчерпывающих операторов переключения. Чтобы быть уверенным, что я все сделал правильно, я использую инструмент статического анализа кода. Итак, давайте углубимся в детали:

  1. Неисчерпывающие операторы switch: они всегда должны иметь значение по умолчанию. Как следует из названия, это утверждения, которые не охватывают все возможные значения. Это также может быть невозможно, например, оператор switch для целочисленного значения или для String. Здесь я хотел бы использовать пример Vanwaril (Следует отметить, что я думаю, что он использовал этот пример, чтобы сделать неправильное предложение. Я использую его здесь, чтобы заявить обратное -> Использовать выражение по умолчанию):

    switch(keystroke)
    {
      case 'w':
        // move up
      case 'a':
        // move left
      case 's':
        // move down
      case 'd':
        // move right
      default:          
        // cover all other values of the non-exhaustive switch statement
    }
    

    Игрок может нажать любую другую клавишу. Тогда мы ничего не могли сделать (это можно показать в коде, просто добавив комментарий к случаю по умолчанию), или это должно, например, напечатать что-нибудь на экране. Этот случай актуален, как это может случиться.

  2. Исчерпывающие операторы переключения: Эти операторы переключения охватывают все возможные значения, например, оператор переключения для перечисления типов систем оценок. При разработке кода в первый раз легко охватить все значения. Однако, поскольку мы люди, есть небольшой шанс забыть о некоторых. Кроме того, если вы добавите значение enum позже, так что все операторы switch должны быть адаптированы, чтобы сделать их исчерпывающими, снова откроется путь в ад ошибки. Простое решение - инструмент статического анализа кода. Инструмент должен проверить все операторы switch и проверить, являются ли они исчерпывающими или имеют ли они значение по умолчанию. Вот пример для исчерпывающего оператора switch. Сначала нам нужно перечисление:

    public enum GradeSystemType {System1To6, SystemAToD, System0To100}
    

    Тогда нам нужна переменная этого перечисления, как GradeSystemType type = .... Исчерпывающий оператор switch будет выглядеть следующим образом:

    switch(type)
    {
      case GradeSystemType.System1To6:
        // do something
      case GradeSystemType.SystemAToD:
        // do something
      case GradeSystemType.System0To100:
        // do something
    }
    

    Поэтому, если мы расширим GradeSystemType, например, System1To3инструмент статического анализа кода должен обнаружить, что предложение по умолчанию отсутствует, а оператор switch не является исчерпывающим, поэтому мы сохраняем.

Еще одна вещь. Если мы всегда используем defaultпредложение, может случиться так, что инструмент статического анализа кода не способен обнаруживать исчерпывающие или не исчерпывающие операторы переключения, поскольку он всегда обнаруживает defaultпредложение. Это очень плохо, так как мы не будем проинформированы, если мы расширим enum другим значением и забудем добавить его в один оператор switch.

ясень
источник
0

Должны ли операторы switch всегда содержать предложение по умолчанию? Случаи переключений не могут существовать без случая по умолчанию, в случае переключателя значение switch(x)по умолчанию вызовет значение переключателя в этом случае x, если оно не совпадает с любыми другими значениями случая.

Нисал Эду
источник
0

Я полагаю, что это довольно специфично для языка и для случая C ++ второстепенный момент для класса enum типа . Который кажется более безопасным, чем традиционное перечисление. НО

Если вы посмотрите на реализацию std :: byte, это выглядит примерно так:

enum class byte : unsigned char {} ;

Источник: https://en.cppreference.com/w/cpp/language/enum

А также учтите это:

В противном случае, если T является типом перечисления, который либо ограничен областью действия, либо имеет область действия с фиксированным базовым типом, и если в braced-init-list есть только один инициализатор, и если преобразование из инициализатора в базовый тип не сужается, и если инициализация - это прямая инициализация списка, затем перечисление инициализируется с результатом преобразования инициализатора в его базовый тип.

(начиная с C ++ 17)

Источник: https://en.cppreference.com/w/cpp/language/list_initialization

Это пример класса enum, представляющего значения, которые не определены перечислителем. По этой причине вы не можете полностью доверять перечислениям. В зависимости от приложения это может быть важно.

Однако мне действительно нравится то, что @Harlan Kassler сказал в своем посте, и я сам начну использовать эту стратегию в некоторых ситуациях.

Просто пример небезопасного класса enum:

enum class Numbers : unsigned
{
    One = 1u,
    Two = 2u
};

int main()
{
    Numbers zero{ 0u };
    return 0;
}
Дэвид Леджер
источник