Следующий код предназначен для создания своего рода тривиального хэша строки длиной до 8 символов:
#include <type_traits>
#include <cstdint>
#include <iostream>
template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n==0,
uint64_t>::type string_hash(const char (&)[N])
{
return 0;
}
template<std::size_t N, std::size_t n=N>
constexpr typename std::enable_if<N<=9 && n!=0,
uint64_t>::type string_hash(const char (&array)[N])
{
return string_hash<N,n-1>(array) | ((array[n-1]&0xffull)<<(8*(n-1)));
}
Для нормальных строковых литералов и constexpr NULL-завершенных строк это действительно работает нормально. Но если я сделаю что-то вроде этого:
constexpr char s2[] = {1,2,3,4,5,6,7,8,9};
std::cout << string_hash(s2) << "\n";
, вывод будет таким же, как для строки "\x1\x2\x3\x4\x5\x6\x7\x8"
, Я пытался добавить static_assert(array[N-1]==0,"Failed");
в определении string_hash
, но компилятор говорит, что array[N-1]
не является константным выражением. Затем я попытался объявить параметр constexpr
, но компилятор сказал, что параметр не может быть объявлен constexpr
,
Как я могу сделать эту проверку?
Пожалуйста, имейте в виду, что хотя constexpr
функции Можно использоваться во время компиляции, они не должны быть. Вы не можете добавить какие-либо статические утверждения к параметрам времени выполнения, потому что статическое утверждение было бы невозможно оценить, когда параметры не известны во время компиляции.
То, что вы можете сделать, это то же самое, что вы можете сделать для неconstexpr
функции: бросить что-нибудь. Это не препятствует тому, чтобы ваша функция вызывалась с неверным вводом, но предотвращает неверные результаты. И когда ваша функция используется в контексте, требующем константного выражения, компилятор правильно обнаружит ее как не возвращающую постоянное значение.
Тело constexpr
Функция должна быть единственным оператором возврата в C ++ 11, но вы все равно можете разместить ее там:
return array[N-1] ? throw "bad!" : <your current return expression here>;
Выберите что-нибудь лучше, чтобы бросить, хотя.
Причина, по которой компилятор жалуется, заключается в том, что array
неизвестно в то время, когда string_hash<N,n>
функция создается static_cast
оценивается при создании экземпляра, а не при вызове (даже если это функция constexpr).
Обратите внимание, что для каждой пары будет создана ровно одна функция. <N,n>
ценности. Если вы используете две строки constexpr одинаковой длины, точно такой же экземпляр string_hash
будет использоваться, но в зависимости от аргумента array[N-1]
может дать другой результат.
Я буду продолжать искать точный ответ на ваш вопрос, если это необходимо. Однако, как «быстрое исправление», могу ли я предложить изменить хеш-функцию, чтобы она всегда включала в расчет последний символ, 0 или нет?
Обновить:
покопавшись, я узнал, что constexpr_assert
это то, что вы, вероятно, хотите в вашем случае, и это в настоящее время отсутствует в стандарте. Надеюсь, они добавят его в будущем. Вы можете проверить: