2148. Hashing enums should be supported directly by std::hash

Section: 22.10.19 [unord.hash] Status: C++14 Submitter: Ville Voutilainen Opened: 2012-04-10 Last modified: 2016-08-03

Priority: Not Prioritized

View all other issues in [unord.hash].

View all issues with C++14 status.

Discussion:

The paper proposes various hashing improvements. What it doesn't mention is hashing of enums; enums are integral types, and users expect them to have built-in hashing support, rather than having to convert enums to ints for uses with unordered containers and other uses of hashes. Daniel Krügler explains in c++std-lib-32412 that this is not achievable with a SFINAEd hash specialization because it would require a partial specialization with a type parameter and a non-type parameter with a default argument, which is currently not allowed, and hence the fixes in N3333 should be adopted instead.

[2012-10 Portland: Move to Open]

We agree this is a real issue that should be resolved, by specifying such a hash.

It is not clear that we should specify this as calling hash on the underlying_type, or whether that is overspecification and we merely require that the hash be supplied.

STL already has shipped an implementation, and is keen to provide wording.

[ 2013-04-14 STL provides rationale and improved wording ]

Rationale:

This can be achieved by inserting a very small tweak to the Standardese. We merely have to require that hash<Key> be valid when Key is an "enumeration type" (which includes both scoped and unscoped enums). This permits, but does not require, hash<Enum> to behave identically to hash<underlying_type<Enum>::type>, following existing precedent — note that when unsigned int and unsigned long are the same size, hash<unsigned int> is permitted-but-not-required to behave identically to hash<unsigned long>.

This proposed resolution doesn't specify anything else about the primary template, allowing implementations to do whatever they want for non-enums: static_assert nicely, explode horribly at compiletime or runtime, etc.

While we're in the neighborhood, this proposed resolution contains an editorial fix. The 22.10 [function.objects] synopsis says "base template", which doesn't appear anywhere else in the Standard, and could confuse users into thinking that they need to derive from it. The proper phrase is "primary template".

[2013-04-18, Bristol]

Proposed resolution:

This wording is relative to N3485.

  1. In 22.10 [function.objects], header functional synopsis, edit as indicated:

    namespace std {
      […]
      // 20.8.12, hash function baseprimary template:
      template <class T> struct hash;
      […]
    }
    
  2. In 22.10.19 [unord.hash]/1 edit as indicated:

    -1- The unordered associative containers defined in 23.5 [unord] use specializations of the class template hash as the default hash function. For all object types Key for which there exists a specialization hash<Key>, and for all enumeration types (9.7.1 [dcl.enum]) Key, the instantiation hash<Key> shall: […]