Я читал в нескольких разных местах, что, используя новые строковые литералы C ++ 11, можно было бы вычислить хэш строки во время компиляции. Однако, похоже, никто не готов выступить и сказать, что это будет возможно или как это будет сделано.
- Это возможно?
- Как бы выглядел оператор?
Меня особенно интересуют подобные варианты использования.
void foo( const std::string& value )
{
switch( std::hash(value) )
{
case "one"_hash: one(); break;
case "two"_hash: two(); break;
/*many more cases*/
default: other(); break;
}
}
Примечание: хеш-функция времени компиляции не должна выглядеть точно так, как я ее написал. Я изо всех сил пытался угадать, как будет выглядеть окончательное решение, но оно meta_hash<"string"_meta>::value
также могло быть жизнеспособным.
c++
metaprogramming
c++11
hash
deft_code
источник
источник
Ответы:
Это немного поздно, но мне удалось реализовать функцию CRC32 во время компиляции с использованием
constexpr
. Проблема в том, что на момент написания он работал только с GCC, а не с компилятором MSVC или Intel.Вот фрагмент кода:
CrcVal01
равно 0x335CC04AНадеюсь, что это поможет вам!
источник
constexpr
недоступен в VS2013, кроме ноября 2013 г. CTP blogs.msdn.com/b/vcblog/archive/2013/11/18/…По крайней мере, согласно моему прочтению §7.1.5 / 3 и §5.19, следующее могло бы быть законным:
Кажется, это соответствует основным правилам в §7.1.5 / 3:
Есть некоторый вопрос,
*input
связано ли s с незаконным преобразованием lvalue в rvalue, и я не уверен, что понимаю правила в §5.19 / 2/6/2 1 и п.4.1 достаточно хорошо , чтобы быть уверенным в том , что.С практической точки зрения этот код принят (например) в g ++, по крайней мере, еще в g ++ 4.7.1.
Использование будет примерно таким:
Однако для соблюдения требований §5.19 / 2/6/2 вам, возможно, придется сделать что-то вроде этого:
источник
constexpr
, 2: У вас нет условия остановки (где*input == nullptr
), и, как я понимаю, уconstexpr
вас не может быть.(unsigned)-1
если он есть; и возвращает 1 для всех остальных строк. Переписать с тернарным условным оператором?Это попытка максимально точно решить проблему ОП.
живой пример .
Обратите внимание на основное отличие -
std::hash
нельзя использовать, поскольку мы не контролируемstd::hash
алгоритм, и мы должны повторно реализовать его какconstexpr
, чтобы оценить его во время компиляции. Кроме того, в нем нет «прозрачных» хэшейstd
, поэтому вы не можете (без созданияstd::string
) хешировать необработанный символьный буфер как файлstd::string
.Я
std::string
вставил пользовательский хешер (с прозрачнойconst char*
поддержкой) вmy_hash
пространство имен, чтобы вы могли сохранить его в файле,std::unordered_map
если вам нужна согласованность.На основе отличного ответа @JerryCoffin и ветки комментариев под ним, но с попыткой написать его с использованием текущих лучших практик C ++ 11 (в отличие от их ожидания!).
Обратите внимание, что использование «сырого хеша» для
switch
оператораcase
опасно. Позже вы захотите провести==
сравнение, чтобы убедиться, что это сработало.источник
Этот фрагмент основан на фрагменте Clement JACOB. Но с лязгом тоже работает. И он должен быть быстрее при компиляции (у него только один рекурсивный вызов, а не два, как в исходном сообщении).
См. Доказательство концепции здесь
источник
Обратите внимание, что показанная здесь форма не была принята в стандарт, как указано ниже.
Предполагается, что обработка строки во время компиляции станет возможной благодаря определяемым пользователем литералам, предложенным в N2765 .
Как я уже упоминал, я не знаю ни одного компилятора, который в настоящее время его реализует, и без поддержки компилятора о работе можно только догадываться.
В пп. 2.13.7.3 и 4 проекта мы имеем следующее:
Объедините это с,
constexpr
и у нас должна получиться обработка строки времени компиляции.update: я упустил из виду, что я читал не тот абзац, эта форма разрешена для определяемых пользователем целочисленных литералов и -floating-literals, но, очевидно, не для -string-literals (§2.13.7.5).
Эта часть предложения, похоже, не была принята.
При этом, с моим ограниченным взглядом на C ++ 0x, это может выглядеть примерно так (скорее всего, я что-то не так понял):
Если подход Джерри работает, то должно работать следующее:
источник
constexpr
определенного пользователем литерала. Я не уверен, что вы можете использовать строковый литерал в качестве параметра шаблона, разве у них нет статической связи? (они есть, по крайней мере, в C ++ 98 и поэтому запрещены как параметры шаблона).operator ""_hash
меня работает в Xcode 5.0.2.Другое решение, основанное на решении Клемента ЯКОБа, использующее constexpr C ++ 11 (а не расширенный C ++ 14), но имеющее только одну рекурсию.
Некоторое объяснение
combine_crc32
позволяет нам сохранять результат рекурсии под переменнойpart
и использовать его дважды. Эта функция - обходной путь для ограничения C ++ 11, запрещающего объявления локальных переменных.ctcrc32
Функция ожидает строковый литерал, который передается в качествеconst char (&)[len]
. Таким образом, мы можем получить длину строки в качестве параметра шаблона и не полагаться на макросы.источник
Следующее работает в GCC 4.6.1, и вы можете использовать любой
hash
илиpack
в блоках переключения.НКУ , казалось бы (?) Не позволяет рекурсивные вызовы , когда мы переходим
s+1
сs
указателем, поэтому я используюoff
переменную.источник
Если у вас есть компилятор c ++ 17 и string_view, это становится тривиальным, просто напишите обычную версию:
источник
crc32("mystring")
(обычно VS имеет тенденцию делать это). Уловка, позволяющая обойти эту проблему, заключается в создании переменной constexpr, которая зависит от оценки времени компиляции вашего crc32. Обычноconstexpr uint32_t val = crc32("mystring");
Вот еще одна реализация C ++ 11 (на основе ответа @ CygnusX1), которая работает как с массивами constexpr char, так и со строками времени выполнения:
Вам нужно,
str.size() + 1
потому чтоlen
во второй перегрузкеstrlen(str) + 1
из-за нулевого символа в конце.Я не добавлял перегрузку,
const char *
потому что она мешает второй перегрузке - вы можете легко добавить перегрузки дляconst char *, size_t
илиstd::string_view
.источник
Это хороший вопрос.
Основываясь на ответе Джерри Коффина, я создал еще один, совместимый с std :: hash Visual Studio 2017.
https://github.com/manuelgustavo/cx_hash
источник
Мне все еще не хватало варианта crc32-literal (что невозможно с шаблонами), поэтому вот мое предложение, основанное на CygnusX1 . Провели небольшое тестирование, не стесняйтесь оставлять отзывы.
Тестет на MSVC.
PS: Я ненавижу искать дополнительные материалы где-то еще, поэтому я скопировал таблицу CRC внизу своего ответа.
Альтернатива с алгоритмом от Дэна Бернштейна (djb2) (комбинированные ответы от Джерри Коффина + Георга Фриче )
Таблица Crc32:
источник