By default, the unordered containers use the ==
operator on the key type to compare elements. They also use an object of type hash<key_type>
to generate the hash code for each element. The library supplies versions of the hash
template for the built-in types, including pointers. It also defines hash
for some of the library types, including string
s and the smart pointer types that we will describe in Chapter 12. Thus, we can directly define unordered containers whose key is one of the built-in types (including pointer types), or a string
, or a smart pointer.
However, we cannot directly define an unordered container that uses a our own class types for its key type. Unlike the containers, we cannot use the hash template directly. Instead, we must supply our own version of the hash
template. We’ll see how to do so in § 16.5 (p. 709).
Instead of using the default hash
, we can use a strategy similar to the one we used to override the default comparison operation on keys for the ordered containers (§ 11.2.2, p. 425). To use Sales_data
as the key, we’ll need to supply functions to replace both the ==
operator and to calculate a hash code. We’ll start by defining these functions:
size_t hasher(const Sales_data &sd)
{
return hash<string>()(sd.isbn());
}
bool eqOp(const Sales_data &lhs, const Sales_data &rhs)
{
return lhs.isbn() == rhs.isbn();
}
Our hasher
function uses an object of the library hash
of string
type to generate a hash code from the ISBN member. Similarly, the eqOp
funciton compares two Sales_data
objects by comparing their ISBNs.
We can use these functions to define an unordered_multiset
as follows
using SD_multiset = unordered_multiset<Sales_data,
decltype(hasher)*, decltype(eqOp)*>;
// arguments are the bucket size and pointers to the hash function and equality operator
SD_multiset bookstore(42, hasher, eqOp);
To simplify the declaration of bookstore
we first define a type alias (§ 2.5.1, p. 67) for an unordered_multiset
whose hash and equality operations have the same types as our hasher
and eqOp
functions. Using that type, we define bookstore
passing pointers to the functions we want bookstore
to use.
If our class has its own ==
operator we can override just the hash function:
// use FooHash to generate the hash code; Foo must have an == operator
unordered_set<Foo, decltype(FooHash)*> fooSet(10, FooHash);
Exercise 11.37: What are the advantages of an unordered container as compared to the ordered version of that container? What are the advantages of the ordered version?
Exercise 11.38: Rewrite the word-counting (§ 11.1, p. 421) and word-transformation (§ 11.3.6, p. 440) programs to use an unordered_map
.