Компилируя следующий код и получил ошибку type illegal
.
int main()
{
// Compilation error - switch expression of type illegal
switch(std::string("raj"))
{
case"sda":
}
}
Вы не можете использовать строку в switch
или case
. Зачем? Есть ли какое-нибудь решение, которое хорошо работает для поддержки логики, похожей на включение строк?
c++
string
switch-statement
yesraaj
источник
источник
QMetaEnum
Ответы:
Причина, почему это связано с системой типов. C / C ++ не поддерживает строки как тип. Он поддерживает идею константного массива char, но не совсем понимает понятие строки.
Чтобы сгенерировать код для оператора switch, компилятор должен понимать, что означает, что два значения равны. Для таких элементов, как int и enums, это тривиальное сравнение битов. Но как компилятор должен сравнивать 2 строковых значения? Чувствителен к регистру, нечувствителен, осведомлен о культуре и т. Д. Без полного понимания строки невозможно дать точный ответ.
Кроме того, операторы переключения C / C ++ обычно генерируются как таблицы ветвей . Не так просто сгенерировать таблицу ветвей для переключения стиля строки.
источник
std::string
были добавлены литералы. Это в основном историческое. Но одна проблема, которая приходит на ум, заключается в том, что при том, какswitch
работает в настоящее время, дубликатыcase
s должны быть обнаружены во время компиляции; однако для строк это может быть не так просто (учитывая выбор локали во время выполнения и т. д.). Я предполагаю, что такая вещь должна была бы потребоватьconstexpr
случаев или добавить неуказанное поведение (никогда, что мы хотим сделать).std::string
значения или дажеstd::string
с массивом const char (а именно с помощью оператора ==), нет технической причины, которая помешала бы компилятору генерировать оператор switch для любого типа, который предоставляет этот оператор. Это могло бы открыть некоторые вопросы о таких вещах, как время жизни ярлыков, но в целом это в первую очередь решение по языку, а не техническая сложность.Как упоминалось ранее, компиляторы любят создавать таблицы поиска, которые оптимизируют
switch
операторы почти до O (1) времени, когда это возможно. Объедините это с тем фактом, что язык C ++ не имеет строкового типа -std::string
это часть стандартной библиотеки, которая сама по себе не является частью языка.Я предложу альтернативу, которую вы, возможно, захотите рассмотреть, я использовал ее в прошлом для хорошего эффекта. Вместо переключения самой строки переключите результат хеш-функции, которая использует строку в качестве входных данных. Ваш код будет почти таким же понятным, как переключение строки, если вы используете предопределенный набор строк:
Существует множество очевидных оптимизаций, которые в значительной степени следуют тому, что компилятор C сделал бы с оператором switch ... забавно, как это происходит.
источник
C ++
хеш-функция constexpr:
источник
operator ""
чтобы сделать код более красивым.constexpr inline unsigned int operator "" _(char const * p, size_t) { return hash(p); }
И используйте это какcase "Peter"_: break;
ДемоC ++ 11 обновление, по-видимому, не @MarmouCorp выше, но http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4067/Switch-on-Strings-in-C.htm
Использует две карты для преобразования между строками и перечислением класса (лучше, чем обычное перечисление, потому что его значения находятся внутри него, и обратный поиск хороших сообщений об ошибках).
Использование static в коде codeguru возможно с поддержкой компилятором списков инициализаторов, что означает VS 2013 plus. GCC 4.8.1 был в порядке, не уверен, насколько дальше он будет совместим.
...
источник
Проблема в том, что по причинам оптимизации оператор switch в C ++ не работает ни с чем, кроме примитивных типов, и вы можете только сравнить их с константами времени компиляции.
Предположительно, причина ограничения заключается в том, что компилятор может применить некоторую форму оптимизации, компилируя код до одной инструкции cmp и перехода, где адрес вычисляется на основе значения аргумента во время выполнения. Поскольку разветвление и циклы и плохо работают с современными процессорами, это может быть важной оптимизацией.
Чтобы обойти это, я боюсь, вам придется прибегнуть к заявлениям if.
источник
std::string
других пользователей первыми в языке и поддержать их в выражении switch с помощью эффективного алгоритма.std::map
+ C ++ 11 лямбда-шаблон без перечисленийunordered_map
для потенциальных амортизированныхO(1)
: Каков наилучший способ использования HashMap в C ++?Вывод:
Использование внутри методов с
static
Чтобы эффективно использовать этот шаблон внутри классов, статически инициализируйте лямбда-карту, иначе вы платите
O(n)
каждый раз за ее создание с нуля.Здесь мы можем избежать
{}
инициализацииstatic
переменной метода: статические переменные в методах класса , но мы также можем использовать методы, описанные в: статические конструкторы в C ++? Мне нужно инициализировать частные статические объектыНеобходимо было преобразовать захват лямбда-контекста
[&]
в аргумент, или это было бы неопределенным: const static auto lambda использовался с захватом по ссылкеПример, который выдает тот же результат, что и выше:
источник
switch
утверждением. Дублирование значений регистра вswitch
выражении является ошибкой во время компиляции. Использованиеstd::unordered_map
молча принимает дубликаты значений.В C ++ и C переключатели работают только с целочисленными типами. Вместо этого используйте лестницу if else. C ++, очевидно, мог бы реализовать какое-то выражение swich для строк - я думаю, никто не посчитал это полезным, и я согласен с ними.
источник
Почему нет? Вы можете использовать реализацию переключателя с эквивалентным синтаксисом и той же семантикой. В
C
языке вообще нет объектов и строковых объектов, но строки в строках сC
нулевым символом в конце, на которые ссылается указатель. ВC++
языке есть возможность создавать функции перегрузки для сравнения объектов или проверки равенства объектов. ВC
качествеC++
достаточно гибкой , чтобы иметь такой переключатель для строк дляC
языка , а также для объектов любого типа, поддержка comparaison или проверка равенства дляC++
языка. А современныеC++11
позволяют иметь этот коммутатор достаточно эффективной реализации.Ваш код будет выглядеть так:
Например, можно использовать более сложные типы
std::pairs
или любые структуры или классы, которые поддерживают операции равенства (или комбинации для быстрого режима).Характеристики
Синтаксические различия с переключением языка
Для
C++97
языка используется линейный поиск. ДляC++11
более современного можно использоватьquick
режим поиска по дереву, где оператор возврата в CASE становится недопустимым.C
Реализация языка существует там , гдеchar*
используются тип и заканчивающийся нуль сравнений.Узнайте больше об этой реализации переключателя.
источник
Чтобы добавить вариант с использованием простейшего возможного контейнера (нет необходимости в упорядоченной карте) ... Я не стал бы беспокоиться с перечислением - просто поместите определение контейнера непосредственно перед переключателем, чтобы было легко увидеть, какое число представляет в каком случае.
Это делает поиск в хэше
unordered_map
и использует связанныйint
для управления оператором switch. Должно быть довольно быстро. Обратите внимание, чтоat
используется вместо того[]
, как я сделал этот контейнерconst
. Использование[]
может быть опасным - если строка отсутствует на карте, вы создадите новое отображение и можете получить неопределенные результаты или постоянно растущую карту.Обратите внимание, что
at()
функция выдаст исключение, если строка отсутствует на карте. Таким образом, вы можете попробовать сначала использоватьcount()
.Ниже приводится версия с тестом для неопределенной строки:
источник
Я думаю, что причина в том, что в C строки не являются примитивными типами, как сказал Томьен, мыслить в строке как массив символов, поэтому вы не можете делать такие вещи, как:
источник
В с ++ строки не являются гражданами первого класса. Строковые операции выполняются через стандартную библиотеку. Я думаю, что это причина. Кроме того, C ++ использует оптимизацию таблицы ветвей для оптимизации операторов регистра переключателя. Посмотрите на ссылку.
http://en.wikipedia.org/wiki/Switch_statement
источник
В C ++ вы можете использовать только оператор switch для int и char
источник
long
иlong long
, который не превратится вint
. Там нет риска усечения там.источник
во многих случаях вы можете получить дополнительную работу, вытащив первый символ из строки и включив его. может случиться так, что вам придется выполнить вложенное переключение на charat (1), если ваши дела начинаются с того же значения. кто-нибудь, читающий ваш код, оценит подсказку
источник
Более функциональный обход проблемы с переключателем:
источник
Вы не можете использовать строку в случае переключения. Разрешены только int и char. Вместо этого вы можете попробовать enum для представления строки и использовать ее в блоке переключателя, например:
Используйте его в этом случае.
источник
Переключатели работают только с целочисленными типами (int, char, bool и т. Д.). Почему бы не использовать карту для сопряжения строки с номером, а затем использовать этот номер с переключателем?
источник
Это потому, что C ++ превращает переключатели в таблицы переходов. Он выполняет тривиальную операцию с входными данными и переходит к нужному адресу без сравнения. Поскольку строка - это не число, а массив чисел, C ++ не может создать таблицу переходов из нее.
(код из Википедии https://en.wikipedia.org/wiki/Branch_table )
источник
cmp
/jcc
реализация может быть такой же действительной в соответствии со стандартом C ++.