使用带有数组作为键的 unordered_map

Using an unordered_map with arrays as keys

我不明白为什么我不能使用 array<int,3> 作为键类型的 unordered_map

#include <unordered_map>

using namespace std;

int main() {

   array<int,3> key = {0,1,2};

   unordered_map< array<int,3> , int >  test;
   test[key]  = 2;

   return 0;
}

我收到一个很长的错误,最相关的部分是

main.cpp:11:9: error: no match for ‘operator[]’ (operand types are std::unordered_map<std::array<int, 3ul>, int>’ and ‘std::array<int, 3ul>’)
 test[key]  = 2;
     ^

数组是否因为缺少一些要求而不符合成为键的条件?

相关错误是

error: no match for call to '(const std::hash<std::array<int, 3ul> >) (const std::array<int, 3ul>&)'

unordered_map 需要密钥的散列,它会寻找 std::hash 的重载来做到这一点。您可以使用合适的散列函数扩展 namespace std

为什么?

http://www.cplusplus.com/reference/unordered_map/unordered_map/

所述

Internally, the elements in the unordered_map are not sorted in any particular order with respect to either their key or mapped values, but organized into buckets depending on their hash values to allow for fast access to individual elements directly by their key values (with a constant average time complexity on average).

现在根据你的问题,我们需要 hash 一个尚未在标准 c++ 内部实现的数组。

如何克服它?

因此,如果您想将 array 映射到一个值,您必须实现自己的 std::hash http://en.cppreference.com/w/cpp/utility/hash for which you might get some help from C++ how to insert array into hash set?.

一些解决方法

如果您可以自由使用 boost 那么它可以为您提供数组和许多其他类型的散列。它基本上使用 hash_combine 方法,您可以查看 http://www.boost.org/doc/libs/1_49_0/boost/functional/hash/hash.hpp.

使用 msvc14 编译出现以下错误:

"The C++ Standard doesn't provide a hash for this type."

我想这是不言自明的。

您必须实现哈希。哈希表取决于对键进行哈希处理,找到一个桶来放入它们。C++ 并不知道如何对每种类型进行哈希处理,在这种特殊情况下,默认情况下它不知道如何对 3 个整数的数组进行哈希处理。您可以像这样实现一个简单的哈希结构:

struct ArrayHasher {
    std::size_t operator()(const std::array<int, 3>& a) const {
        std::size_t h = 0;

        for (auto e : a) {
            h ^= std::hash<int>{}(e)  + 0x9e3779b9 + (h << 6) + (h >> 2); 
        }
        return h;
    }   
};

然后使用它:

unordered_map< array<int,3> , int, ArrayHasher >  test;

编辑:我将用于组合哈希的函数从简单的异或更改为 boost 为此目的使用的函数:http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html。这应该足够强大,可以实际使用。