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

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

Другие вопросы по тегам