Страницы

Поиск по вопросам

Показаны сообщения с ярлыком switch. Показать все сообщения
Показаны сообщения с ярлыком switch. Показать все сообщения

среда, 26 февраля 2020 г.

Switch quantity on integer | *** wasnt declared in this scope

#cpp #условия #switch

#include 


using namespace std;

/* run this program using the
console pauser or add your own getch,
system("pause") or input loop */

int main(int argc, char** argv) {
    string lang;
    cout << "Choose your language: rus/eng" << endl;
    cin >> lang;
    switch (lang) { //здесь первая ошибка switch quantity on integer
        case eng:
            cout << "You choose english" << endl; //тут
            break;
        case rus:
            cout << "You choose russian" << endl; //и тут вторая ошибка rus(в случае
выше eng) wasnt declared in this scope
            break;
    }
    return 0;
}


Не первый раз ошибка *** wasnt declared in this scope, так и не могу понять в чем дело
    


Ответы

Ответ 1



switch нельзя использовать с string. Используйте if ... else

Ответ 2



switch нельзя использовать с string.

понедельник, 10 февраля 2020 г.

Switch-on-strings Java7 - архив переписки JSR 334

#java #строки #switch

Здравствуйте. Может ли мне кто-нибудь объяснить небольшой момент в переписки, касательно
критики и предложений данного нововведедения switch-on-strings в 7 пакете Жабы, в 334
coin project 334 JSR ?

процитирую: 

Now that we plan to have closures, do we still need strings-in-switch?
Won't a string-to-function map be about as fast (though maybe less
convenient)? I don't know what the use cases are for
strings-in-switch, but the feature already felt a bit low-benefit to
me, and seems even more so now with closures.


ссылка на источник

Что такое понятие closures, и почему в случае его реализации, задается вопрос, существует
ли необходимость в данной опции-свичире ?
Какая между ними связь, объясните для непонимающего.
И так же на счет вопроса не будет ли string-to-function map не менее быстрым.

Может кто небольшое введение сделать для понимания данного коммента ?
Буду благодарен. 
    


Ответы

Ответ 1



Могу ошибаться, но мне кажется, здесь речь идет о замыканиях, т.е. лямбдах. Пример, где switch может быть заменен лямбда-функцией. public static String caseOnString(String str) { switch (str) { case "hello": return "world"; case "bye": return "country"; default: return ""; } } public static String mapOnString(String str) { Function map = s -> { if (s.equals("hello")) return "world"; if (s.equals("bye")) return "country"; return ""; }; return map.apply(str); }

Ответ 2



Думаю, имели в виду следующее: если у нас есть переменная String str, то вместо switch (str) { case "one": System.out.println(1); break; case "two": System.out.println(2); break; default: System.out.println("?"); } предлагали писать что-то вроде такого (closures - это замыкания, а в случае java - лямбды, хоть они и не полноценные замыкания): Map switchMap = new HashMap<>(); switchMap.put("one", () -> System.out.println(1)); switchMap.put("two", () -> System.out.println(2)); switchMap.getOrDefault(str, () -> System.out.println("?")).run();

Кастомный Switch с подписями

#jquery #css #button #animate #switch

Есть Switch с подписями, при клике на сам switch он должен переключаться, так же
переключение может происходить при клике на значение.





.switch input {
  display: none;
}
.switch {
  width: 45px;
  height: 15px;
  position: relative;
  display: inline-block;
}
.slider {
  position: absolute;
  cursor: pointer;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: #00cc8c;
  transition: .3s;
}
.slider:before {
  content: "";
  height: 26px;
  width: 26px;
  position: absolute;
  left: 0;
  bottom: -5px;
  background-color: #008f62;
  transition: .3s;
}
input:checked + .slider {
  background-color: #f8ee7c;
}
input:focus + .slider {
  box-shadow: 0 0 1px #f8ee7c;
}
input:checked + .slider:before {
  transform: translateX(26px);
}
.slider.br {
  border-radius: 34px;
}
.slider.br:before {
  border-radius: 50%;
}





Возможно подключение jQuery. Сама изюминка вопроса в добавлении активных надписей
"Вкл/Выкл"

https://fiddle.jshell.net/w4t05476/
    


Ответы

Ответ 1



CSS: .selector-on { color: gray; cursor: pointer; } .selector-off { color: gray; cursor: pointer; } .switch input{ display:none; } .active-selector { color: #00cc8c; } .switch{ width: 45px; height: 15px; position: relative; display: inline-block; } .slider{ position: absolute; cursor: pointer; top: 0; right: 0; bottom: 0; left: 0; background-color: #00cc8c; transition: .3s; } .slider:before{ content: ""; height: 26px; width: 26px; position: absolute; left: 0; bottom: -5px; background-color: #008f62; transition: .3s; } input:checked + .slider{ background-color: #f8ee7c; } input:focus + .slider{ box-shadow: 0 0 1px #f8ee7c; } input:checked + .slider:before{ transform: translateX(26px); } .slider.br{ border-radius: 34px; } .slider.br:before{ border-radius: 50%; } HTML: On Off jQuery: function enableDisable(flag) { $('.my-checkbox').prop('checked', flag); $('.selector-on').toggleClass('active-selector', function() { return $(this).hasClass('active-selector') ? true : false; }); $('.selector-off').toggleClass('active-selector', function() { return $(this).hasClass('active-selector') ? true : false; }); } $('.selector-on').on('click', function(event) { return $(this).hasClass('active-selector') ? false : enableDisable(false); }); $('.selector-off').on('click', function(event) { return $(this).hasClass('active-selector') ? false : enableDisable(true); }); $('.my-checkbox').on('click', function() { if($(this).prop('checked')) { $('.selector-off').trigger('click'); } else { $('.selector-on').trigger('click'); } }); Пример

Ответ 2



$('input[type=checkbox]').before('On').after('Off'); $('input[type=checkbox]').onchange(function(){ $('#label_before').toggleClass('label_active'); $('#label_after').toggleClass('label_active'); }) Это если имеет смысл добавлять элементы через jQ. Я бы предпочел сразу все в html вставлять/через пхп генерить, не знаю, как там завязано у Вас все, но так не красиво, да и работает в идеале с одним свитчем. Код не тестировался, работоспособность не гарантируется. Гарантируется только смысл.

Ответ 3



.b-switch { margin: 15px 35px; font-family: 'segoe ui', sans-serif; font-size: 12px; } .b-switch input[type="checkbox"] { display: none; } .b-switch input[type="checkbox"] + label { width: 55px; height: 15px; position: relative; display: inline-block; background-color: #00cc8c; border-radius: 35px; transition: .3s; } .b-switch input[type="checkbox"] + label:before{ content: ""; position: absolute; left: -35px; top: 0; width: calc(100% + 70px); height: 100%; cursor: pointer; } .b-switch input[type="checkbox"] + label:after { content: ""; position: absolute; left: 0; bottom: -5px; height: 26px; width: 26px; background-color: #008f62; border-radius: 50%; cursor: pointer; transition: .3s; } .b-switch input[type="checkbox"] + label > span, .b-switch input[type="checkbox"] + label + span{ position: absolute; text-transform: uppercase; padding: 0 5px; color: #008F62; font-weight: 600; cursor: pointer; } .b-switch input[type="checkbox"] + label > span{ right: 100%; } .b-switch input[type="checkbox"]:checked + label{ background-color: #f8ee7c; } .b-switch input[type="checkbox"]:checked + label:after { left: calc(100% - 26px); } .b-switch input[type="checkbox"]:checked + label > span, .b-switch input[type="checkbox"] + label + span{ opacity: .5; pointer-events: none; } .b-switch input[type="checkbox"]:checked + label + span{ opacity: 1; }
Выкл
Выкл
Выкл


среда, 1 января 2020 г.

Чистый код: Switch

#любой_язык #switch #рефакторинг

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


Ответы

Ответ 1



Вы подходите не совсем правильно. Разбивать функцию на части нужно не по формальным признакам («длинный switch»), а по логическим. Вы должны задать себе вопрос: имеет ли ваш кусок кода самостоятельный смысл? (Например: можно ли сказать несколькими словами, что именно этот кусок делает?) Если ответ на этот вопрос положительный, вынесите этот кусок в функцию, и назовите её этими самыми словами. Если отрицательный — оставляйте всё как было. Небольшое дополнение. Кодировать switch можно по-разному. Можно оставить его как switch. Если это отображение одного объекта на другой, можно закодировать его как выборку из std::unordered_map. А возможно, ваш switch лучше представить в виде вызова виртуальной функции. Когда именно и как правильно — снова-таки зависит от смысла. Пример: string text; switch (code) { case 100: text = "Continue"; break; case 101: text = "Switching protocols"; break; case 200: text = "OK"; break; case 301: text = "Moved permanently"; break; case 404: text = "Not found"; break; } по идее лучше закодировать так: unordered_map message_text { { 100, "Continue" }, { 101, "Switching protocols" }, { 200, "OK" }, { 301, "Moved permanently" }, { 404, "Not found" } }; и в коде string s = message_text[200]; или там string s; auto it = message_text.find(200); if (it != message_text.end()) s = it->second; (и выделить в отдельную функцию GetHttpMessageByCode). Пример того, когда switch разумно заменить на иерархию классов: switch (employee_kind) { case EmployeeKind::regular: salary = get_base_salary(); bonus = total_profit * bonus_ratio / number_of_employees; break; case EmployeeKind::external: salary = get_work_hours * get_hourly_rate(employee_id); bonus = 0; break; case EmployeeKind::manager: salary = get_base_salary(); bonus = bonus_fund / number_of_managers; if (salary < 100) bonus += 100 - salary; break; } Такой код можно заменить на иерархию классов: class employee { protected: int get_base_salary() { return 0; } public: virtual void compute_salary_and_bonus() = 0; }; class regular_employee : public employee { public: virtual void compute_salary_and_bonus() { salary = get_base_salary(); bonus = total_profit * bonus_ratio / number_of_employees; } }; class expernal_employee : public employee { public: virtual void compute_salary_and_bonus() { salary = get_work_hours() * get_hourly_rate(); bonus = 0; } }; class manager : public employee { public: virtual void compute_salary_and_bonus() { salary = get_base_salary(); bonus = bonus_fund / number_of_managers; if (salary < 100) bonus += 100 - salary; } };

Ответ 2



Зависит от того, когда читабельность будет выше. Если у Вас какой-то простой перекодировщик, то логично вынести в отдельный метод int charToInt(char a) { switch (a) { case '0': return 0; case '1': return 1; case '2': return 2; ........... default: throw "Error char" } } (да, я знаю, что можно кастануть к int и вычесть 0x30) Если же у Вас какой-то парсер switch (a) { case '0': ........ break; case '1': ........ break; default: throw "Error char" } то лучше оставить в одном методе. Тем более, что могут понадобиться дополнительные переменные, которые используются в этом методе Наверное, общий совет будет такой - если Вы можете вынести switch в метод, который принимает ровно один аргумент, а все break можете заменить на return, то выносите

Ответ 3



Зависит от предпочтений. Я например - выношу и даю название CheckSomething - something это то, что проверяется :) И не забудте в любом случае default case :)

вторник, 31 декабря 2019 г.

c switch default

#c #switch #case

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

#include 
int main()
{
    int a = 123;
    const char *r = "initial value";
    switch (a) {
        case 1: r = "1"; break;
        if (0) {
            default: r = "not 1";
        }
    }
    puts(r);
    return 0;
}


нормально компилируется GCC и выдает при исполнении

not 1


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


Ответы

Ответ 1



Тело switch (как и тело while, do/while, for и т.п) это просто statement, в котором мы расставляем метки case и default, и в котором возможно использование break. Не более того. Метки case и default могут появляться только внутри statement, принадлежащего какому-то switch, но в остальном ограничения, накладываемые на расстановку этих меток, ничем не отличаются от любых других меток. Аналогичным образом передача управления на эти метки происходит по правилам, похожим на правила goto, с той только разницей, что передать управление на метку case и default может только ее непосредственно охватывающий switch. В вашем случае, если заменить метки case и default на "обычные" метки, мы получим просто составной statement { l1: r = "1"; break; if (0) { l2: r = "not 1"; } } Ничего необычного в этом составном statement-е нет. Положение меток в нем не нарушает никаких правил языка. В том, что метка default: передает управление внутрь ветки некоего if, нет ничего необычного. Вас никто не заставляет даже использовать именно составной statement для реализации тела switch, т.е. вопреки распространенной практике тело switch не обязательно должно быть заключено в {}. Вы можете воспользоваться любым другим типом statament и расставить метки в нем int i = rand() % 4; switch (i) if (0) case 0: printf("Privet!\n"); else if (0) case 1: printf("Hello!\n"); else if (0) case 2: printf("World!\n"); else default: printf("Ku-ku!\n"); Обратите внимание, что эта замечательная техника написания switch избавляет вас от необходимости помнить о break в конце каждой ветки.

Ответ 2



код явно с такой ошибкой, что даже компилироваться не должен В коде нет никаких синтаксических ошибок, почему он не должен компилироваться? А с точки зрения логики обработки switch получается так: if( a == 1 ) goto label_case_1; else goto label_default; label_case_1: r = "1"; goto case_end; if(0) { /* этот if никак не влияет на видимость метки */ label_default: r = "not 1"; } case_end: puts(r);

понедельник, 30 декабря 2019 г.

Оператор switch, нужен ли break после метки default?

#cpp #switch

Какой смысл в операторе break после метки default, если оператор switch после default
итак завершает свою работу?

Часто вижу примеры, как с break так и без после default:

switch(number)
{
  case 0: cout << "Too small.\n";  break;
  case 1: cout << "One.\n";  break;
  case 2: cout << "Two.\n"; break;       
  case 3: cout << "Three.\n"; break;
  default: cout << "Too large.\n"; 
  break; // какой смысл в этом break?
}

    


Ответы

Ответ 1



Синтаксически, нет необходимости в самом последнем break, причём неважно в какой секции он находится. switch(number) { case 1: cout << 1; break; case 2: cout << 2; break; default: case 0: cout << "Мало"; break; case 3: cout << "Много"; /*break;*/ } По сути, break - это goto на позицию сразу за фигурной скобкой. (А continue на позицию перед ней, но только в циклах) В этом свете, очевидна излишнесть этого оператора. Однако, этот break всё ещё может быть полезен, если список случаев (case) может изменяться в будущем. При наличии всех break сложнее ошибиться и получить вот такую ошибку: switch(number) { case 1: cout << 1; break; case 2: cout << 2; break; default: case 0: cout << "Мало"; break; case 3: cout << 3; // При добавлении строчки, забыли добавить пропущенный break case 4: cout << "Много"; } Это становится более актуальным, если секции не такие тривиальные, и просто окинув взглядом switch не сразу понятно, что к чему относится.

пятница, 20 декабря 2019 г.

switch case C++

#cpp #строки #switch

Почему этот код не работает? Неужели в C++ switch не принимает тип string это же
чушь какая-то.

string text;
cin>>text;
switch(text){
    case "n":
        std::cout << "Some output";
        break;
    default:
        std::cout<<"Input incorrect!";
        break;
}
return 0;

    


Ответы

Ответ 1



string нельзя использовать в switch. Кажется, char* можно, но бесполезно. А вот char - вполне пойдёт, правда, в таком случае все строки, начинающиеся на n будут подходить под условие. string text; cin>>text; switch (text[0]) { case 'n': std::cout << "Some output"; break; default: std::cout<<"Input incorrect!"; break; } return 0;

Ответ 2



6.4.2 стандарта: Оператор switch вызывает передачу управления на один из нескольких операторов, в зависимости от значения условия. Условие должно иметь целочисленный тип, перечислимый тип или классовый тип. Если условие имеет классовый тип, то оно контекстуально неявно преобразуется (глава 4) в целочисленный или перечислимый тип. Если тип условия (возможно, преобразованный) подлежит целочисленным расширениям (4.5), то значение преобразуется к расширенному типу. Как вы понимаете, string не целочисленное, не перечислимый тип и нет неявного преобразования в таковой :) Вообще-то switch - не синтаксический сахар для if-elseif-else, у него своя специфика, связанная с производительностью ("По-моему, так" (с) Пух :))

Ответ 3



Да, именно так, в С++ конструкция switch / case может оперировать только с целыми числами, енумераторами, или классами, приводимыми к целому типу, или енумератору: 9.4.2 The switch statement [stmt.switch] 2 The condition shall be of integral type, enumeration type, or class type. If of class type, the condition is contextually implicitly converted (Clause 7) to an integral or enumeration type. If the (possibly converted) type is subject to integral promotions (7.6), the condition is converted to the promoted type. Any statement within the switch statement can be labeled with one or more case labels as follows: case constant-expression : where the constant-expression shall be a converted constant expression (8.20) of the adjusted type of the switch condition.

суббота, 14 декабря 2019 г.

Сложные условия в switch

#java #switch

Есть if, а есть switch. Если использовать if то "или" будет записываться как ( условие
| условие ). Можно ли сделать подобное в при помощи switch? Моя кривая интуиция:

int x = 10
switch (x){
    case 1| case 2:
        ...
}


Конечно же, можно не парится, и записать это как:

switch (x){
    case 1:
        ...
    case 2:
        ...
}


...Но такой способ прошу не рассматривать.
    


Ответы

Ответ 1



В примерах кода часто вижу вторую реализацию, скорее всего — это стандарт: switch (x){ case 1: case 2: ... break; case 3: ... break; } В комментариях подтвердили, что это стандарт. Вот документация с сайта Oracle — ссылка.

четверг, 5 декабря 2019 г.

Чем конструкция switch плоха?

#switch

Не раз слышал что конструкция switch это плохо. Например вот в этой статье, пункт
10 Но ни разу не слышал почему и когда он плох. Кто что думает по этому поводу?    


Ответы

Ответ 1



Когда говорят про плохие switch, обычно имеют ввиду примеры следующего рода. Другое дело, что, в принципе, в конструкции switch как таковой нет ничего плохого и не стоит сразу же реплейсить все switch'и в своем коде на сложные иерархии классов. В тех случаях, когда такой рефакторинг действительно оправдан, вопросов возникать не должно.

Ответ 2



На самом деле предубеждение к switch существует с тех времен, когда компиляторы были неоптимизирующими. Тогда switch превращался в огромный набор условных операторов, что нельзя назвать лучшим решением. Зато выглядело это аккуратнее, чем такой же набор if'ов в исходном коде программе. Сейчас же компилятор, когда видит switch использует либо дерево из условных переходов (что-то в духе такого, см. также), либо использует таблицу переходов. В последнем случае создается таблица вида :<адрес перехода> из которой выбирается нужный адрес, по которому лежит соответствующий индексу код. Можно догадаться, что это существенно эффективнее, чем сравнивать каждое значение соответствующего case. Так что теперь switch не очень страшен. С другой стороны, при использовании конструкции switch-case не нужно забывать про особенности работы с ключевыми словами break и default. Некоторые забывают, например, слово break и в результате имеют некорректное выполнение программы (выполняется не только нужный case, но и последующие, пока не встретится break) Что еще хочу сказать. switch хорошо работает с константными целыми или перечислимыми типами. В этом случае компилятор даже может подсказать, что есть проблема. Например, с помощью предупреждения. Например, для gcc: -Wswitch Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. (The presence of a default label prevents this warning.) case labels outside the enumeration range also provoke warnings when this option is used (even if there is a default label). This warning is enabled by -Wall. -Wswitch-default Warn whenever a switch statement does not have a default case. -Wswitch-enum Warn whenever a switch statement has an index of enumerated type and lacks a case for one or more of the named codes of that enumeration. case labels outside the enumeration range also provoke warnings when this option is used. The only difference between -Wswitch and this option is that this option gives a warning about an omitted enumeration code even if there is a default label.

Ответ 3



Плохость или хорошесть конструкции switch зависит от того во что ее превращает компилятор. Проиллюстрирую в псевдокоде: Конструкция switch switch(i) { case 0: do0; case 1: do1; case 2: do2; default: doDefault; } может превратиться, либо в (вариант №1): if(i==0) do0; else if(i==1) do1; else if(i==2) do2; else doDefault; или же в (вариант №2): switch(i) { 0: do0; 1: do1; 2: do2; default: doDefault; } Отличие состоит в том, что в первом варианте с if-else условие проверяется каждый раз, а во втором условие проверяется 1 раз создается таблица переходов. Очевидно, что 2-й вариант реализации быстрее и удобнее. Скажем в Java все именно так и устроено. Да и вообще в более-менее любом нормальном современном компиляторе так и устроено. В древних компиляторах часто реализовывалось через 1-ю конструкцию if-else - оттуда видимо и предубеждение против switch

понедельник, 8 июля 2019 г.

Имеет ли значение порядок “case-ов” в структуре “switch case”?

Я работаю с болшим количеством данных и они проходят через множество switch case операторов.
Есть ли разница в том как расределять case-ы внутри структуры? Будет ли более продуктивным поднять более часто встречаюшиеся случаи на первые строчки? Т.е. разбиваеться ли эта структура внутри на "if else" компоненты?
Работаю на java, но предполагаю что одинаковый подзод будет и в Сишеках.


Ответ

Для таких языков как Си, C++, C# - производительность весьма слабо зависит от количества блоков case и вовсе не зависит от их порядка (все равно компилятор их переупорядочит как ему нужно).
Для языка Java - производительность еще как зависит от порядка блоков, а иногда еще и результат может меняться (если вы используете класс с некорректной реализацией equals). Потому что компилятор Java преобразует оператор switch во что-то вроде серии "if - else if - else if - else"

суббота, 20 апреля 2019 г.

Switch-on-strings Java7 - архив переписки JSR 334

Здравствуйте. Может ли мне кто-нибудь объяснить небольшой момент в переписки, касательно критики и предложений данного нововведедения switch-on-strings в 7 пакете Жабы, в 334 coin project 334 JSR ?
процитирую:
Now that we plan to have closures, do we still need strings-in-switch? Won't a string-to-function map be about as fast (though maybe less convenient)? I don't know what the use cases are for strings-in-switch, but the feature already felt a bit low-benefit to me, and seems even more so now with closures.
ссылка на источник
Что такое понятие closures, и почему в случае его реализации, задается вопрос, существует ли необходимость в данной опции-свичире ? Какая между ними связь, объясните для непонимающего. И так же на счет вопроса не будет ли string-to-function map не менее быстрым.
Может кто небольшое введение сделать для понимания данного коммента ? Буду благодарен.


Ответ

Могу ошибаться, но мне кажется, здесь речь идет о замыканиях, т.е. лямбдах.
Пример, где switch может быть заменен лямбда-функцией.
public static String caseOnString(String str) { switch (str) { case "hello": return "world"; case "bye": return "country"; default: return ""; } }
public static String mapOnString(String str) { Function map = s -> { if (s.equals("hello")) return "world"; if (s.equals("bye")) return "country"; return ""; };
return map.apply(str); }

понедельник, 15 апреля 2019 г.

switch case C++

Почему этот код не работает? Неужели в C++ switch не принимает тип string это же чушь какая-то.
string text; cin>>text; switch(text){ case "n": std::cout << "Some output"; break; default: std::cout<<"Input incorrect!"; break; } return 0;


Ответ

string нельзя использовать в switch. Кажется, char* можно, но бесполезно. А вот char - вполне пойдёт, правда, в таком случае все строки, начинающиеся на n будут подходить под условие.
string text; cin>>text;
switch (text[0]) { case 'n': std::cout << "Some output"; break;
default: std::cout<<"Input incorrect!"; break; }
return 0;

пятница, 5 апреля 2019 г.

Оператор switch, нужен ли break после метки default?

Какой смысл в операторе break после метки default, если оператор switch после default итак завершает свою работу?
Часто вижу примеры, как с break так и без после default
switch(number) { case 0: cout << "Too small.
"; break; case 1: cout << "One.
"; break; case 2: cout << "Two.
"; break; case 3: cout << "Three.
"; break; default: cout << "Too large.
"; break; // какой смысл в этом break? }


Ответ

Синтаксически, нет необходимости в самом последнем break, причём неважно в какой секции он находится.
switch(number) { case 1: cout << 1; break; case 2: cout << 2; break; default: case 0: cout << "Мало"; break; case 3: cout << "Много"; /*break;*/ }
По сути, break - это goto на позицию сразу за фигурной скобкой. (А continue на позицию перед ней, но только в циклах) В этом свете, очевидна излишнесть этого оператора.

Однако, этот break всё ещё может быть полезен, если список случаев (case) может изменяться в будущем. При наличии всех break сложнее ошибиться и получить вот такую ошибку:
switch(number) { case 1: cout << 1; break; case 2: cout << 2; break; default: case 0: cout << "Мало"; break; case 3: cout << 3; // При добавлении строчки, забыли добавить пропущенный break case 4: cout << "Много"; }
Это становится более актуальным, если секции не такие тривиальные, и просто окинув взглядом switch не сразу понятно, что к чему относится.

среда, 9 января 2019 г.

Чистый код: Switch

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


Ответ

Вы подходите не совсем правильно. Разбивать функцию на части нужно не по формальным признакам («длинный switch»), а по логическим. Вы должны задать себе вопрос: имеет ли ваш кусок кода самостоятельный смысл? (Например: можно ли сказать несколькими словами, что именно этот кусок делает?)
Если ответ на этот вопрос положительный, вынесите этот кусок в функцию, и назовите её этими самыми словами. Если отрицательный — оставляйте всё как было.

Небольшое дополнение. Кодировать switch можно по-разному. Можно оставить его как switch. Если это отображение одного объекта на другой, можно закодировать его как выборку из std::unordered_map. А возможно, ваш switch лучше представить в виде вызова виртуальной функции.
Когда именно и как правильно — снова-таки зависит от смысла. Пример:
string text; switch (code) { case 100: text = "Continue"; break; case 101: text = "Switching protocols"; break; case 200: text = "OK"; break; case 301: text = "Moved permanently"; break; case 404: text = "Not found"; break; }
по идее лучше закодировать так:
unordered_map message_text { { 100, "Continue" }, { 101, "Switching protocols" }, { 200, "OK" }, { 301, "Moved permanently" }, { 404, "Not found" } };
и в коде
string s = message_text[200];
или там
string s; auto it = message_text.find(200); if (it != message_text.end()) s = it->second;
(и выделить в отдельную функцию GetHttpMessageByCode).

Пример того, когда switch разумно заменить на иерархию классов:
switch (employee_kind) { case EmployeeKind::regular: salary = get_base_salary(); bonus = total_profit * bonus_ratio / number_of_employees; break; case EmployeeKind::external: salary = get_work_hours * get_hourly_rate(employee_id); bonus = 0; break; case EmployeeKind::manager: salary = get_base_salary(); bonus = bonus_fund / number_of_managers; if (salary < 100) bonus += 100 - salary; break; }
Такой код можно заменить на иерархию классов:
class employee { protected: int get_base_salary() { return 0; } public: virtual void compute_salary_and_bonus() = 0; };
class regular_employee : public employee { public: virtual void compute_salary_and_bonus() { salary = get_base_salary(); bonus = total_profit * bonus_ratio / number_of_employees; } };
class expernal_employee : public employee { public: virtual void compute_salary_and_bonus() { salary = get_work_hours() * get_hourly_rate(); bonus = 0; } };
class manager : public employee { public: virtual void compute_salary_and_bonus() { salary = get_base_salary(); bonus = bonus_fund / number_of_managers; if (salary < 100) bonus += 100 - salary; } };

понедельник, 24 декабря 2018 г.

c switch default

Привет. Пытаясь ответит на один из вопросов здесь, с удивлением обнаружил, что следующий код
#include int main() { int a = 123; const char *r = "initial value"; switch (a) { case 1: r = "1"; break; if (0) { default: r = "not 1"; } } puts(r); return 0; }
нормально компилируется GCC и выдает при исполнении
not 1
Мне кажется, что код явно с такой ошибкой, что даже компилироваться не должен. В чем тут дело?


Ответ

Тело switch (как и тело while, do/while, for и т.п) это просто statement, в котором мы расставляем метки case и default, и в котором возможно использование break. Не более того.
Метки case и default могут появляться только внутри statement, принадлежащего какому-то switch, но в остальном ограничения, накладываемые на расстановку этих меток, ничем не отличаются от любых других меток.
Аналогичным образом передача управления на эти метки происходит по правилам, похожим на правила goto, с той только разницей, что передать управление на метку case и default может только ее непосредственно охватывающий switch
В вашем случае, если заменить метки case и default на "обычные" метки, мы получим просто составной statement
{ l1: r = "1"; break; if (0) { l2: r = "not 1"; } }
Ничего необычного в этом составном statement-е нет. Положение меток в нем не нарушает никаких правил языка. В том, что метка default: передает управление внутрь ветки некоего if, нет ничего необычного.
Вас никто не заставляет даже использовать именно составной statement для реализации тела switch, т.е. вопреки распространенной практике тело switch не обязательно должно быть заключено в {}. Вы можете воспользоваться любым другим типом statament и расставить метки в нем
int i = rand() % 4; switch (i) if (0) case 0: printf("Privet!
"); else if (0) case 1: printf("Hello!
"); else if (0) case 2: printf("World!
"); else default: printf("Ku-ku!
");
Обратите внимание, что эта замечательная техника написания switch избавляет вас от необходимости помнить о break в конце каждой ветки.

понедельник, 22 октября 2018 г.

Сложные условия в switch

Есть if, а есть switch. Если использовать if то "или" будет записываться как ( условие | условие ). Можно ли сделать подобное в при помощи switch? Моя кривая интуиция:
int x = 10 switch (x){ case 1| case 2: ... }
Конечно же, можно не парится, и записать это как:
switch (x){ case 1: ... case 2: ... }
...Но такой способ прошу не рассматривать.


Ответ

В примерах кода часто вижу вторую реализацию, скорее всего — это стандарт:
switch (x){ case 1: case 2: ... break; case 3: ... break; }

В комментариях подтвердили, что это стандарт. Вот документация с сайта Oracle — ссылка

среда, 17 октября 2018 г.

Странности со switch

Обнаружил для себя такую неожиданную вещь: код
switch (a) { case 1: std::string alfa; break; case 2: break; default: break; }
не компилируется из-за объявления переменной класса string. Компилятор выдает, что не может прыгнуть к следующей метке:
1.cpp:16:9: error: cannot jump from switch statement to this case label default: ^
Но почему так? Почему, если объявить, например, переменную типа int, то все в порядке?


Ответ

Смотрите - а что ему делать, если вы получите a==2 и при этом решите в ветви обратиться к этой переменной alfa? Инициализировать ее? нет?
Во избежание таких фокусов - перепрыгивания через инициализацию - это считается ошибкой.
Просто возьмите переменную в фигурные скобки, чтоб ограничить область видимости:
switch (a) { case 1: { std::string alfa; } break; case 2: break; default: break; }