You can, of course, convert unordered_map to another data structure that has a guaranteed order and use it to generate a hash.
A better idea would be to hash each individual element of the map, put these hashes in vector , and then sort and combine the hashes. See for example How to combine hash values in C ++ 0x? to combine hashes.
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; }
Testing this on shuffled vectors shows that it always returns the same hash.
Now, to adapt this basic concept specifically for working with unordered_map . Since the unordered_map iterator returns a pair , we also need a hash function.
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> >()); } }; }
See in action: http://ideone.com/WOLFbc
source share