It’s unclear to me from the C++11 standard where user-defined hash<T> functors should be defined.
For example, in 23.5.2 Header <unordered_map>, it shows:
template <class Key,
class T,
class Hash = hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T> > >
class unordered_map;
This suggests that, by default, hash<T> is searched for in the global namespace, whereas equal_to<> is searched for in the std namespace.
Why the difference in namespace between hash<> and equal_to<>?
(Actually, in the description at http://www.cplusplus.com/reference/unordered_map/unordered_map/, neither specifies the std namespace.)
Thus, when defining a hash<> functor for a user type, should we enclose it within a namespace std { } block, or can it remain in the current namespace?
If the code does not have a using namespace std;, how do the STL containers like unordered_map know to look in the std namespace for the predefined hash<> functors associated with the primitive types? It seems like the default Hash = hash<Key> would fail to find these.
Sorry if these are stupid questions..
First of all, there is no “argument dependent lookup” for templates. So
hash<Key>will always refer to the same template, either instdor in global namespace, independent ofKey. If it had resolved to different templates in different translation units, it would cause undefined behavior by ODR violation. This alone suggests thathashhere meansstd::hash, that is as-ifunordered_mapwas declared like this:However, the types declared in the standard headers are not required to be written in source (they could be in principle built-in to the compiler or pre-compiled by some other magic). The standard requires each standard header to declare only the types in its synopsis, which means that by omitting the
std::hashdeclaration the standard permits some hypothetical implementation to avoid the above namespace pollution. This explains why you do not see the above declaration in the synopsis.To further back-up the above conclusion, we go to §20.8.12 Class template hash [unord.hash] that reads:
This paragraph refers to the
std::hash, which we can infer from the synopsis of<functional>.Bottom line: This is an inconsistency in the standard formatting. There are plenty of inconsistencies, so this specific case is not surprising at all. In such cases one has to understand what has been intended by deducing what is the only sensible thing.
Specialization. You specialize templates in the namespace that they were declared. You are explicitly granted the right to specialize standard templates for your own type: