C/C++ случай переключения со строкой
Возможный дубликат:
C / C++: переключатель для нецелых
Привет, мне нужно использовать строку в случае переключателя. Мое решение до сих пор заключалось в том, чтобы вычислить хэш строки с помощью моей хэш-функции. Проблема в том, что я должен вручную предварительно рассчитать все мои значения хеш-функции для строк. Есть ли лучший подход?
h=_myhash (mystring);
switch (h)
{
case 66452:
.......
case 1342537:
........
}
10 ответов
Просто используйте if() { } else if () { }
цепь. Использование значения хеша будет кошмаром обслуживания. switch
предназначен для низкоуровневого оператора, который не подходит для сравнения строк.
Вы можете сопоставить строки с указателем на функцию, используя стандартную коллекцию; выполнение функции, когда совпадение найдено.
РЕДАКТИРОВАТЬ: Используя пример в статье, на которую я дал ссылку в своем комментарии, вы можете объявить тип указателя на функцию:
typedef void (*funcPointer)(int);
и создайте несколько функций для соответствия подписи:
void String1Action(int arg);
void String2Action(int arg);
Карта будет std::string
в funcPointer
:
std::map<std::string, funcPointer> stringFunctionMap;
Затем добавьте строки и указатели на функции:
stringFunctionMap.add("string1", &String1Action);
Я не проверял ни один из кодов, которые я только что опубликовал, это не в моей голове:)
Как правило, вы используете хеш-таблицу и объект функции, оба доступны в Boost, TR1 и C++0x.
void func1() {
}
std::unordered_map<std::string, std::function<void()>> hash_map;
hash_map["Value1"] = &func1;
// .... etc
hash_map[mystring]();
Это немного больше накладных расходов во время выполнения, но в несколько раз более приемлемо. Хеш-таблицы предлагают O(1) вставку, поиск и т. Д., Что делает их такими же сложными, как и таблица переходов в стиле сборки.
Лучший способ - использовать генерацию исходного кода, чтобы вы могли использовать
if (hash(str) == HASH("some string") ..
в вашем основном источнике, и шаг перед сборкой преобразует HASH(const char*)
выражение в целочисленное значение.
Предложение Руслика использовать генерацию исходного кода мне кажется хорошим. Однако я бы не стал использовать понятие "основные" и "сгенерированные" исходные файлы. Я предпочел бы иметь один файл с кодом, почти идентичным вашему:
h=_myhash (mystring);
switch (h)
{
case 66452: // = hash("Vasia")
.......
case 1342537: // = hash("Petya")
........
}
Следующее, что я бы сделал, я бы написал простой сценарий. Perl хорош для такого рода вещей, но ничто не мешает вам даже написать простую программу на C/C++, если вы не хотите использовать какие-либо другие языки. Этот скрипт или программа будет брать исходный файл, читать его построчно, находить все case NUMBERS: // = hash("SOMESTRING")
строк (используйте здесь регулярные выражения), замените NUMBERS фактическим значением хеш-функции и запишите измененный источник во временный файл. Наконец, он создаст резервную копию исходного файла и заменит его временным файлом. Если вы не хотите, чтобы в исходном файле каждый раз была новая отметка времени, программа может проверить, действительно ли что-то было изменено, и если нет, пропустить замену файла.
Последнее, что нужно сделать, - это интегрировать этот скрипт в используемую систему сборки, чтобы случайно не забыть запустить его перед сборкой проекта.
Вы можете создать хеш-таблицу. Ключи могут быть строкой, а значение может быть и целым числом. Установите целые числа для значений в качестве констант, а затем вы можете проверить их с помощью switch
,
Если вы после выступления и не хотите проходить через все if
каждый раз, если их много или нужно хэшировать значения, вы можете отправить дополнительную информацию в функцию с помощью enum
или просто добавьте enum
введите в вашей структуре.
У вас нет хорошего решения вашей проблемы, так что вот хорошее решение;-)
Он сохраняет вашу эффективность, когда утверждения отключены, а когда утверждения включены, он вызовет ошибку подтверждения, если хеш-значение неверно.
Я подозреваю, что язык программирования D может вычислять значение хеша во время компиляции, таким образом устраняя необходимость явной записи значения хеша.
template <std::size_t h>
struct prehash
{
const your_string_type str;
static const std::size_t hash_value = h;
pre_hash(const your_string_type& s) : str(s)
{
assert(_myhash(s) == hash_value);
}
};
/* ... */
std::size_t h = _myhash(mystring);
static prehash<66452> first_label = "label1";
switch (h) {
case first_label.hash_value:
// ...
;
}
Кстати, рассмотрите возможность удаления начального подчеркивания из объявления _ myhash () (извините, но stackru заставляет меня вставить пробел между _ и myhash). Реализация на C++ свободна для реализации макросов с именами, начинающимися с подчеркивания и заглавной буквы (пункт 36 "Исключительного стиля C++" Херба Саттера), поэтому, если вы привыкнете давать имена вещей, начинающиеся с подчеркивания, то прекрасный день может появиться, когда вы дадите символу имя, которое начинается с подчеркивания и заглавной буквы, где реализация определила макрос с тем же именем.
Вы можете использовать эту строку для индексации в хеш-таблицу указателей функций.
Изменить: glib имеет реализацию хэш-таблицы, которая поддерживает строки в качестве ключей и произвольные указатели в качестве значений: http://library.gnome.org/devel/glib/stable/glib-Hash-Tables.html
Вы можете использовать перечисление и карту, так что ваша строка станет ключом, а значение перечисления является значением для этого ключа.