Ответ 1
Просто используйте цепочку if() { } else if () { }
. Использование хеш-значения будет кошмаром для обслуживания. switch
предназначен для описания низкого уровня, который не подходит для сравнения строк.
Возможный дубликат:
C/С++: переключатель для нецелых чисел
Привет, Мне нужно использовать строку в корпусе коммутатора. Мое решение до сих пор заключалось в том, чтобы вычислить хэш строки с моей хэш-функцией. Проблема в том, что мне приходится вручную предварительно вычислять все мои хэш-значения для строк. Есть ли лучший подход?
h=_myhash (mystring);
switch (h)
{
case 66452:
.......
case 1342537:
........
}
Просто используйте цепочку 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 и С++ 0x.
void func1() {
}
std::unordered_map<std::string, std::function<void()>> hash_map;
hash_map["Value1"] = &func1;
// .... etc
hash_map[mystring]();
Это немного больше накладных расходов во время выполнения, но в bajillion раз более ремонтопригодным. Таблицы хэшей предлагают O (1) вставку, поиск и т.д., Что делает их такой же сложностью, как таблица перехода в стиле сборки.
Лучший способ - использовать генерацию источника, чтобы вы могли использовать
if (hash(str) == HASH("some string") ..
в вашем основном источнике, а шаг предварительной сборки преобразует выражение HASH(const char*)
в целочисленное значение.
Вы можете использовать строку для индексирования в хеш-таблицу указателей функций.
Изменить: glib имеет реализацию хеш-таблицы, которая поддерживает строки как ключи и произвольные указатели как значения: http://library.gnome.org/devel/glib/stable/glib-Hash-Tables.html
Вы можете создать хеш-таблицу. Ключи могут быть строкой, а значение может быть и целым. Настройте целые числа для значений как константы, а затем вы можете проверить их с помощью switch
.
Вы можете использовать перечисление и карту, поэтому ваша строка станет ключом, а значение перечисления - значением для этого ключа.
Если вы выполняете работу и не хотите каждый раз выполнять все предложения if
, если их много или нужно хэш-значений, вы можете отправить дополнительную информацию в функцию с помощью enum
или просто добавьте тип enum
в вашу структуру.
Нет хорошего решения вашей проблемы, так что это решение okey, -)
Он сохраняет эффективность, когда утверждения отключены, и когда утверждения разрешены, он вызывает ошибку утверждения, если значение хэша неверно.
Я подозреваю, что язык программирования 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() (извините, но stackoverflow заставляет меня вставлять пробел между _ и myhash). Реализация С++ позволяет реализовать макросы с именами, начинающимися с подчеркивания и заглавной буквой (пункт 36 "Исключительный стиль С++" от Herb Sutter), поэтому, если вы привыкли давать имена вещей, которые начинают подчеркивать, тогда прекрасный день может появиться, когда вы дадите символ имя, которое начинается с подчеркивания и заглавной буквы, где реализация определила макрос с тем же именем.
Предложение Ruslik использовать исходное поколение мне кажется хорошим. Тем не менее, я бы не пошел с концепцией "основных" и "сгенерированных" исходных файлов. Я бы предпочел иметь один файл с кодом, почти идентичным вашему:
h=_myhash (mystring);
switch (h)
{
case 66452: // = hash("Vasia")
.......
case 1342537: // = hash("Petya")
........
}
Следующее, что я сделал бы, я бы написал простой script. Perl хорош для таких вещей, но ничто не мешает вам даже писать простую программу на C/С++, если вы не хотите использовать какие-либо другие языки. Этот script или программа возьмет исходный файл, прочитает его по очереди, найдет все эти строки case NUMBERS: // = hash("SOMESTRING")
(используйте здесь регулярные выражения), замените NUMBERS на фактическое значение хэша и напишите измененный источник в временный файл. Наконец, он будет поддерживать исходный файл и заменять его временным файлом. Если вы не хотите, чтобы ваш исходный файл имел новую метку времени каждый раз, программа могла проверить, действительно ли что-то было изменено, а если нет, пропустите замену файла.
Последнее, что нужно сделать, - это интегрировать этот script в используемую систему сборки, чтобы вы случайно не запустили ее, прежде чем строить проект.