Почему оператор switch нельзя применять к строкам? - PullRequest
193 голосов
/ 16 марта 2009

Компилируя следующий код и получил ошибку type illegal.

int main()
{
    // Compilation error - switch expression of type illegal
    switch(std::string("raj"))
    {
    case"sda":
    }
}

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

Ответы [ 19 ]

4 голосов
/ 03 июля 2016

Чтобы добавить вариант, используя самый простой из возможных контейнеров (нет необходимости в упорядоченной карте) ... Я бы не стал беспокоиться о enum - просто поместите определение контейнера непосредственно перед переключателем, чтобы его было легко увидеть какое число представляет какой случай.

Это выполняет хешированный поиск в unordered_map и использует связанный int для управления оператором switch. Должно быть довольно быстро. Обратите внимание, что at используется вместо [], так как я сделал этот контейнер const. Использование [] может быть опасным - если строка отсутствует на карте, вы создадите новое отображение и можете получить неопределенные результаты или постоянно растущую карту.

Обратите внимание, что функция at() сгенерирует исключение, если строка отсутствует на карте. Так что вы можете сначала протестировать, используя count().

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
switch(string_to_case.at("raj")) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;


}

Ниже приведена версия с тестом для неопределенной строки:

const static std::unordered_map<std::string,int> string_to_case{
   {"raj",1},
   {"ben",2}
};
switch(string_to_case.count("raj") ? string_to_case.at("raj") : 0) {
  case 1: // this is the "raj" case
       break;
  case 2: // this is the "ben" case
       break;
  case 0: //this is for the undefined case

}
3 голосов
/ 16 марта 2009

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

http://en.wikipedia.org/wiki/Switch_statement

3 голосов
/ 16 марта 2009

В C ++ вы можете использовать только оператор switch для int и char

0 голосов
/ 16 марта 2009

Вы не можете использовать строку в случае переключения. Разрешены только int и char. Вместо этого вы можете попробовать enum для представления строки и использовать ее в блоке переключателя, например

enum MyString(raj,taj,aaj);

Используйте его в своем заявлении case.

0 голосов
/ 08 марта 2016
    cout << "\nEnter word to select your choice\n"; 
    cout << "ex to exit program (0)\n";     
    cout << "m     to set month(1)\n";
    cout << "y     to set year(2)\n";
    cout << "rm     to return the month(4)\n";
    cout << "ry     to return year(5)\n";
    cout << "pc     to print the calendar for a month(6)\n";
    cout << "fdc      to print the first day of the month(1)\n";
    cin >> c;
    cout << endl;
    a = c.compare("ex") ?c.compare("m") ?c.compare("y") ? c.compare("rm")?c.compare("ry") ? c.compare("pc") ? c.compare("fdc") ? 7 : 6 :  5  : 4 : 3 : 2 : 1 : 0;
    switch (a)
    {
        case 0:
            return 1;

        case 1:                   ///m
        {
            cout << "enter month\n";
            cin >> c;
            cout << endl;
            myCalendar.setMonth(c);
            break;
        }
        case 2:
            cout << "Enter year(yyyy)\n";
            cin >> y;
            cout << endl;
            myCalendar.setYear(y);
            break;
        case 3:
             myCalendar.getMonth();
            break;
        case 4:
            myCalendar.getYear();
        case 5:
            cout << "Enter month and year\n";
            cin >> c >> y;
            cout << endl;
            myCalendar.almanaq(c,y);
            break;
        case 6:
            break;

    }
0 голосов
/ 23 сентября 2016

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

0 голосов
/ 24 марта 2016

Это потому, что C ++ превращает переключатели в таблицы переходов. Он выполняет тривиальную операцию с входными данными и переходит на нужный адрес без сравнения. Поскольку строка - это не число, а массив чисел, C ++ не может создать таблицу переходов из нее.

movf    INDEX,W     ; move the index value into the W (working) register from memory
addwf   PCL,F       ; add it to the program counter. each PIC instruction is one byte
                    ; so there is no need to perform any multiplication. 
                    ; Most architectures will transform the index in some way before 
                    ; adding it to the program counter

table                   ; the branch table begins here with this label
    goto    index_zero  ; each of these goto instructions is an unconditional branch
    goto    index_one   ; of code
    goto    index_two
    goto    index_three

index_zero
    ; code is added here to perform whatever action is required when INDEX = zero
    return

index_one
...

(код из википедии https://en.wikipedia.org/wiki/Branch_table)

0 голосов
/ 18 ноября 2018

Более функциональный обход проблемы с коммутатором:

class APIHandlerImpl
{

// define map of "cases"
std::map<string, std::function<void(server*, websocketpp::connection_hdl, string)>> in_events;

public:
    APIHandlerImpl()
    {
        // bind handler method in constructor
        in_events["/hello"] = std::bind(&APIHandlerImpl::handleHello, this, _1, _2, _3);
        in_events["/bye"] = std::bind(&APIHandlerImpl::handleBye, this, _1, _2, _3);
    }

    void onEvent(string event = "/hello", string data = "{}")
    {
        // execute event based on incomming event
        in_events[event](s, hdl, data);
    }

    void APIHandlerImpl::handleHello(server* s, websocketpp::connection_hdl hdl, string data)
    {
        // ...
    }

    void APIHandlerImpl::handleBye(server* s, websocketpp::connection_hdl hdl, string data)
    {
        // ...
    }
}
0 голосов
/ 11 августа 2012

Переключатели работают только с целочисленными типами (int, char, bool и т. Д.). Почему бы не использовать карту для сопряжения строки с номером, а затем использовать этот номер с переключателем?

...