Вы, конечно, можете преобразовать unordered_map
в какую-то другую структуру данных с гарантированным порядком и использовать ее для генерации хэша.
Лучше всего было бы хешировать каждый отдельный элемент карты, поместить эти хеши в vector
, а затем отсортировать и объединить хеши. См., Например, Как объединить хеш-значения в C ++ 0x? для объединения хешей.
template<typename Hash, typename Iterator>
size_t order_independent_hash(Iterator begin, Iterator end, Hash hasher)
{
std::vector<size_t> hashes;
for (Iterator it = begin; it != end; ++it)
hashes.push_back(hasher(*it));
std::sort(hashes.begin(), hashes.end());
size_t result = 0;
for (auto it2 = hashes.begin(); it2 != hashes.end(); ++it2)
result ^= *it2 + 0x9e3779b9 + (result<<6) + (result>>2);
return result;
}
Проверка этого на перетасованных векторах показывает, что он всегда возвращает один и тот же хэш.
Теперь адаптируем эту базовую концепцию для работы с unordered_map
. Поскольку итератор unordered_map
возвращает pair
, нам также нужна хеш-функция для этого.
namespace std
{
template<typename T1, typename T2>
struct hash<std::pair<T1,T2> >
{
typedef std::pair<T1,T2> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
{
result_type const h1 ( std::hash<T1>()(s.first) );
result_type const h2 ( std::hash<T2>()(s.second) );
return h1 ^ (h2 + 0x9e3779b9 + (h1<<6) + (h1>>2));
}
};
template<typename Key, typename T>
struct hash<std::unordered_map<Key,T> >
{
typedef std::unordered_map<Key,T> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& s) const
{
return order_independent_hash(s.begin(), s.end(), std::hash<std::pair<Key,T> >());
}
};
}
Посмотрите, как это работает: http://ideone.com/WOLFbc
person
Mark Ransom
schedule
27.08.2014