TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #1022 3.89K
switch
#новичкам

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

Сегодня проясним особенности, а в следующий раз поговорим о кейсах применимости.

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

switch(status_code) {
case 200: // OK
processSuccess();
break;
// ...
case 400: // Bad Request
logClientError(status_code);
break;
// ...
case 500: // Service Unavailable
logServerError(status_code);
break;
// ...
default:
handleUnknownStatus(status_code);
break;
}


То есть 1 переменная - много вариантов развития событий.

Теперь погнали по особенностям:

👉🏿 Вы будете проваливаться в нижележащие кейсы, если не напишите break в конце текущего кейса. Это накладывает свои когнитивные сложности, но дает и возможности. Если у вас одинаково обрабатываются разные значения, то вы можете проваливаться в нижележащие кейсы, пока не дойдете до нужного обработчика и не брякнитесь(встретите break):

switch(status_code) {
case 200: // OK
processSuccess();
break;
case 400: // Bad Request
case 401: // Unauthorized
case 403: // Forbidden
case 404: // Not Found
logClientError(status_code);
break;
}


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

Существуют расширения компилятора, которые позволяют указывать в switch диапазон:

switch(x) {
case 0 ... 9: // GNU Extension
std::cout << "0-9\n";
break;
case 10 ... 19: // GNU Extension
std::cout << "10-19\n";
break;
}


Но это непереносимо и вообще не для этого розочка цвела. switch хорошо оптимизируется через jump table(вместо кучи if-else с линейной сложностью используется массив меток обработчиков, в котором за О(1) ищется нужный), а диапазоны значений в эту концепцию не вписываются.

👉🏿 В С++ очень органично вписаны объекты и пользовательские типы, наряду с тривиальными С-совместимыми типами. Поэтому может сложиться впечатление, что switch может, например, со строками работать. Но нет, он работает только с целочисленными типами, то есть с целыми числами и перечислениями(scoped и unscoped).

Если хотите выбирать обработчики на основе пользовательских типов, нужно использовать ассоциативные контейнеры:

using Handler = std::function<void()>;
std::unordered_map<std::string, Handler> handlers = {
{"start", &start},
{"stop", []{ stop(); }}
};

void execute(const std::string& cmd) {
if (auto it = handlers.find(cmd); it != handlers.end()) {
it->second();
}
}



👉🏿 Значения кейсов должны быть константными выражениями. То есть значениями, известными на этапе компиляции. Вы не можете выбрать обработчик, соотвествующий runtime значению.

При использовании enum'ов такой проблемы в принципе не возникает, но вот с int'ами да:

constexpr int getValue() {
return 10;
}

int main() {
constexpr int y = getValue();
int z = getValue();

int x = 10;

switch (x) {
case y: // OK: y - constant expression
std::cout << "x equals y\n";
break;
case z: // ERROR: z is runtime value
std::cout << "x equals z\n";
break;
default:
std::cout << "default\n";
}

return 0;
}



Вроде простая конструкция, но все равно есть нюансы.

Explore nuances. Stay cool.

#cppcore
  • ❤ 22
  • 👍 11
  • 🔥 7
  • ⚡ 2
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →