std::map как альтернатива switch для строк

Вы могли случайно попасть на эту страницу из поиска, разыскивая информацию по switch. Если произошло такое недоразумение, то вам в тему switch в C++ для начинающих

Для непосредственно этой темы необходимо понимание:

  • Требуется, чтобы ваш компилятор умел работать со стандартной библиотекой STL

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

  • В С++ существует определённое ограничение на использование switch: switch может принимать только такое значение, которое умеет сводиться к целочисленному типу

В switch можно отдавать целочисленную переменную, константу-перечисление, либо объект класса, который умеет неявно приводиться к целочисленному типу.

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

Многие люди по инерции пытаются свести всё к switch: хеш функции, вставка в map строки и какого-нибудь номера, что-то ещё выдумывают. Хотя вместо того, чтобы придумывать обход ограничения, можно пойти на поводу у компилятора и не использовать switch для строк вообще. И это, как ни странно, будет лучшим выбором.

В очень старых компиляторах нет возможности использовать такие библиотеки, как stl или boost, поэтому с ними сложнее. Не только в старых компиляторах, но и в современных расширениях языка С++ могут быть проблемы. Я не знаю, как правильно сформулировать: суть в том, что я буду использовать библиотеку STL, которую можно использовать не повсюду. Там, где STL использовать нельзя, приходится или писать, или искать готовый велосипед, который будет аналогичен объекту стандартной библиотеки.

В стандартной библиотеке шаблонов, в STL, определён тип map, он же — ассоциативный массив. Этот тип в огромном числе компиляторов представляет собой красно-черное дерево, AVL-tree. Тип map мы и будем использовать для того, чтобы справиться с задачей выбора действия, исходя из значения строки.

Конечно, пример этот выглядит хуже, чем если бы можно было использовать switch, но благодаря такому подходу не приходится шаманить, что-то выдумывать или думать о разнице в скорости if и switch. Поверьте, здесь скорость достаточно быстрая, AVL-дерево это всё-таки двоичное дерево поиска, сбалансированное по высоте. В общем, ищет очень быстро. К тому же ничего дополнительно вычислять не нужно.

Чтобы разобраться в этом примере, нужно понять, что такое указатели на функции. В map я вставлял тип string и тип указатель на функцию. В итоге получился эффект связи значения строки с функцией. На само создание функции имеются какие-то накладные расходы, но ведь и в switch, возможно, всё свелось бы к использованию функций. Можно и не использовать указатели на функции в параметрах шаблона map (в угловых скобках), но тогда сам код имеет потенциал выглядеть пострашнее. В таком виде, как сейчас, код достаточно удобочитаем и однозначно быстр.

Немного поясню сам пример. После того, как связи строки с сопутствующей ей функции налажены, можно легко использовать значение строки для вызова сопутствующей ей функции. Для этого используется find из map.

map — это класс.
find — это функция-член, описанная внутри класса map

По названию find можно интуитивно понять, что это выполнение поиска в контейнере map. В find отдаётся значение, которое ищется внутри контейнера, если значение найдено, то возвращается итератор на найденный элемент, если не найдено, то возвращается итератор на конец контейнера. Чтобы два раза не выполнять поиск по контейнеру, был объявлен отдельный итератор it, который и есть результат поиска. В зависимости от того, на что указывает этот итератор-результат поиска, выбирается действие: если в контейнере нет строки, то и сопутствующей ей функции скорее всего нет, а если есть строка, то вызывается функция с помощью вот такого синтаксиса:
it->second();

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

Такая вот существует ненапряжная альтернатива.

Можно ещё использовать лямбда-функции, либо функторы, но в корне ситуация не изменится, нужно будет указывать для класса map параметры, второй из которых имеет тип, соответствующий функции.

Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

Добавить комментарий

Ваш e-mail не будет опубликован.

Поиск

 
     
Яндекс.Метрика

НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

В чем заключается многозадачность Windows? Она глючит и pаботает одновpеменно.

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок