web-dev-qa-db-ja.com

配列をキーとしてunordered_mapを使用する

キータイプとしてunordered_mapを使用してarray<int,3>を使用できない理由がわかりません。

#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;
     ^

アレイはいくつかの要件を満たしていないため、キーになる資格がありませんか?

10
Adrien

なぜですか?

http://www.cplusplus.com/reference/unordered_map/unordered_map/ で述べたように

内部的には、unordered_map内の要素は、キー値またはマップされた値のいずれかに関して特定の順序で並べ替えられませんが、ハッシュ値に応じてバケットに編成され、キー値によって直接個々の要素にすばやくアクセスできるようになります(定数を使用)平均時間計算量)。

今、あなたの質問に従って、標準のc ++で内部的に実装されていない配列をhashする必要があります。

それを乗り越える方法は?

したがって、arrayを値にマップする場合は、独自のstd :: hashを実装する必要があります http://en.cppreference.com/w/cpp/utility/hash for C++ハッシュセットに配列を挿入する方法は? から助けを得るかもしれません。

いくつかの回避策

boostを自由に使用できる場合は、配列や他の多くのタイプのハッシュを提供できます。基本的にはhash_combineメソッドを使用しており、これを見ることができます http://www.boost.org/doc/libs/1_49_0/boost/functional/hash/hash.hpp

8

関連するエラーは

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

unordered_mapはキーのハッシュを必要とし、それを行うためにstd::hashのオーバーロードを探します。適切なハッシュ関数を使用してnamespace stdを拡張できます。

8
alain

ハッシュを実装する必要があります。キーのハッシュに応じてテーブルをハッシュし、それらを配置するバケットを見つけます。C++は、すべての型をハッシュする方法を魔法のように知りません。この特定のケースでは、デフォルトで3つの整数の配列をハッシュする方法を知りません。次のような単純なハッシュ構造体を実装できます。

struct ArrayHasher {
    std::size_t operator()(const std::array<int, 3>& a) {
        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;

編集:ハッシュを組み合わせる関数を、単純なxorから、この目的でboostで使用される関数に変更しました: http://www.boost.org/doc/libs/1_35_0/doc/html/boost/ hash_combine_id241013.html 。これは、実際に使用するのに十分な堅牢性を備えている必要があります。

8
Nir Friedman

Msvc14でコンパイルすると、次のエラーが発生します。

「C++標準はこのタイプのハッシュを提供していません。」

これは一目瞭然だと思います。

2
Ervin Szilagyi