With a Regular Type, I mean the definition of Stepanov in Elements of Programming, basically, that there's the concept of equality and that objects which are copies of each other compare equal.
So when you have a Regular Type T
, and the equality relation is transitive (a == b && b == c => a == c), you can define a (non-trivial) hash function which is consistent with the definition of equality (a == b => h(a) == h(b)). Always.
But the standard doesn't include many std::hash
specialisations. E.g. std::complex
doesn't have one, and neither have the containers, with the notable exceptions of vector<bool>
and bitset
.
So I'm wondering what the design principle is here.
Or, asked differently: Are there reasons not to provide std::hash
specialisations for your own types, provided they are regular and equality is transitive?
size_t operator()(T& const) const { return 0; }
The question is, can you always define one that is good for an arbitrary type? – Unscrewvector<bool>
is not implemented asvector
ofbool
s. It's a template specialization that relies onint
to save severalbool
s (I assume 32). It's invariant to any template parameters (and the underlying types'std::hash
), I think that's why a specialization is provided. – Celloidinstd::hash
– Bronchoscopeauto h(auto x) { return x == 0 ? 0 : hash_bits(&x, sizeof x); }
). But when you drop transitivity, then you cannot define a consistent hash function (at least in the cases I saw, e.g.a == b <=> abs(a-b) < 1e-6
). – Eastwardunordered_set
), then you get a consistent hash function. – Eastward