9

std::unordered_set初めて使うのですが、ハッシュ関数について質問があります。私の知る限り、ハッシュ関数を指定しないと、デフォルトでstd::hash<Key>.

mySetのクラスの1つにメンバーがいます:

typedef std::unordered_set<MyClass> USetType;
USetType mySet;

ビルドしようとすると、次のエラーが発生します。

エラー C2440: '型キャスト': 'const MyClass' から 'size_t' に変換できません

カスタムクラスでsize_t使いたい場合、変換関数(to)を定義する必要はありますか? unordered_set独自のハッシュ関数を作成せずにデフォルトを使用する方法はありますか?

4

2 に答える 2

14

テンプレート引数として独自のハッシュファンクターを指定しない場合、デフォルトでになりますstd::hash<MyClass>。これは、定義しない限り存在しません。

std::hash内部名前空間の独自の専門分野を定義するのが最適stdです:

namespace std {
  template <>
  struct hash<MyClass>
  {
    typedef MyClass      argument_type;
    typedef std::size_t  result_type;

    result_type operator()(const MyClass & t) const
    {
       /* ..calculate hash value for t */
    }
  };
}

また、ハッシュを宣言する前に、必ずこのコードを含めてください。std::unordered_set<MyClass>このようにして、テンプレート引数を追加する必要がないのと同じように、ハッシュを宣言できます。

内部の外観を指定しませんでしMyClassたが、一般的な状況では、ユーザー定義型は、デフォルトのハッシュ関数が存在するいくつかの単純型メンバーで構成されています。この場合、個々のタイプのハッシュ値を組み合わせ全体のハッシュ値に結合することをお勧めします。Boostライブラリは、hash_combineこの目的のために呼び出される関数を提供します。もちろん、特定のケースでうまく機能するという保証はありませんが(データ値の分布と衝突の可能性によって異なります)、優れた使いやすい開始点を提供します。

MyClassこれは、2つの文字列メンバーで構成されていると仮定した場合の使用方法の例です。

#include <unordered_set>
#include <boost/functional/hash.hpp>

struct MyClass
{
  std::string _s1;
  std::string _s2;
};

namespace std {
  template <>
  struct hash<MyClass>
  {
    typedef MyClass      argument_type;
    typedef std::size_t  result_type;

    result_type operator()(const MyClass & t) const
    {
      std::size_t val { 0 };
      boost::hash_combine(val,t._s1);
      boost::hash_combine(val,t._s2);
      return val;
    }
  };
}

int main()
{
  std::unordered_set<MyClass> s;
  /* ... */
  return 0;
}
于 2012-11-21T04:06:07.587 に答える