Здравствуйте, andyp, Вы писали:
A> Вот сейчас в с++20 введут прозрачные хешеры и компараторы, а проблема-то частично останется — ты для того, что ищешь, будешь всегда считать хеш. Платишь за то, что тебе не уперлось из-за кривого интерфейса.
Интерфейс, конечно, кривой. Но прозрачные хэши как раз уже сейчас позволяют не считать хэш повторно от констант.
В программе ты сам делаешь выбор: считать ли хэш от string_view каждый раз, либо посчитать его однажды и положить рядом:
// строка + хэш
struct hashed_string_view: std::string_view {
constexpr hashed_string_view(std::string_view v);
size_t cached_hash = 0;
};
Так потратишь несколько лишних байт, но зато вычисление хэша очень будет быстрым:
return this->cached_hash;. Это бывает само по себе полезно, например, когда ключи большие и хэш от них считается медленно.
И в комбинации с прозрачным хэшированием такой класс отлично работает:
struct string_hash {
using is_transparent = void;
constexpr std::size_t operator()(const std::string_view str) const { return my_hash_impl(str); } // вычисляем хэш динамически
constexpr std::size_t operator()(const hashed_string_view& str) const { return str.cached_hash; } // достаём предпосчитанное значение
};
consteval hashed_string_view operator""_svh(const char* str, size_t len) {
return hashed_string_view{std::string_view{str, len}};
}
Теперь, если использовать
string_hash в качестве хэшера для мапы, то от констант значение хэша будет посчитано сразу:
std::unordered_multimap<std::string, ValueType, string_hash, std::equal_to<>> map;
auto it = map.find("key"_svh);
Демо и сравнение.
A> проблема-то частично останется
Хотя упрёк справедливый, потому из коробки не работает:
В старом коде нужно включать поддержку прозрачности явно из-за параноидальной обратной совместимости;
Готового mixin-класса для кэширования хэшей в стандартной библиотеки нет;
Хэш функцию тоже нужно подставлять свою, из-за возможности рандомизации std::hash<string_view>, из-за чего её в общем случае нельзя вычислять от константных литералов во время компиляции (и не важно, что никто этой возможностью не пользуется) .
Каждый пункт решается в одну-две строчки, но этого уже достаточно, чтобы куча кода так и оставалось работать с неэффективными значениями по умолчанию.