You cannot implement qHash
with boost::hash_range
/boost::hash_combine
(which is what pmr's answer does, effectively), because QSet
is the Qt equivalent of std::unordered_set
, and, as the STL name suggests, these containers are unordered, whereas the Boost Documentation states that hash_combine
is order-dependent, ie. it will hash permutations to different hash values.
This is a problem because if you naively hash-combine the elements in stored order
you cannot guarantee that two sets that compare equal are, indeed, equal, which is one of the requirements of a hash function:
For all x, y: x == y => qHash(x) == qHash(y)
So, if your hash-combining function needs to produce the same output for any permutation of the input values, it needs to be commutative. Fortunately, both (unsigned) addition and the xor operation just fit the bill:
template <typename T>
inline uint qHash(const QSet<T> &set, uint seed=0) {
return std::accumulate(set.begin(), set.end(), seed,
[](uint seed, const T&value) {
return seed + qHash(value); // or ^
});
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…