Specializing std::hash for std::array
What is a "good" hash function?

The requirement of a hash function is that it always produces the same value for a given key (in the same instance of the program) and a good hash function should produce each output with equal probability.

Your function achieves this (multiplying by a prime such as 31 is a well-known way of combining hash values to reduce collisions caused by different permutations of the same values).

However, it's up to you to decide whether the hash inputs in your application have a random distribution, or whether they have some pattern that may perturb the output distribution from the hash function.

Can you use your mental reasoning to force a collision?  {1, 0} and {0, 31} might do it, for example.  Can you think of any reason why your code might produce collisions more often than by independent chance?

Style points

The code is neat and clear.  It might be an idea to allow an alternative to std::hash&lt;T&gt; to be supplied by the caller, just as std::unordered_map itself allows a user-supplied hasher.  This may be useful with char* strings, for example.

You could simplify the loop, as std::array supports range-based for:

    for (const auto&amp; element: key) {
        result = result * 31 + hasher(element);
    }


More tests

It's good that you've provided a test suite.  Consider whether you could add more tests - at least one test with an element type other than int and at least least one with different array lengths (you should probably include a test for std::array&lt;char, 1&gt; as a boundary case, for example).

Alternatives

Boost provides a hash() function that accepts built-in (i.e. C-style) arrays, so you might be able to reinterpret_cast the std::array.  I've never tried this, but I don't see why it wouldn't work...