_std::unordered_set<Key>
_および_std::unordered_map<Key, Value>
_でユーザー定義のキータイプをサポートするには、operator==(Key, Key)
とハッシュファンクターを提供する必要があります。
_struct X { int id; /* ... */ };
bool operator==(X a, X b) { return a.id == b.id; }
struct MyHash {
size_t operator()(const X& x) const { return std::hash<int>()(x.id); }
};
std::unordered_set<X, MyHash> s;
_
タイプX
にdefaultハッシュを付けて_std::unordered_set<X>
_だけを記述する方が便利です。コンパイラとライブラリ。相談後
include\c++\4.7.0\bits\functional_hash.h
_include\xfunctional
_std::hash<X>::operator()
を特殊化することが可能であるようです:
_namespace std { // argh!
template <>
inline size_t
hash<X>::operator()(const X& x) const { return hash<int>()(x.id); } // works for MS VC10, but not for g++
// or
// hash<X>::operator()(X x) const { return hash<int>()(x.id); } // works for g++ 4.7, but not for VC10
}
_
C++ 11のコンパイラサポートはまだ実験的であるため、Clangを試していませんでした---、これらは私の質問です:
名前空間std
にそのような特殊化を追加することは合法ですか?私はそれについて複雑な気持ちを持っています。
C++ 11標準に準拠しているstd::hash<X>::operator()
バージョンはどれですか?
ポータブルな方法はありますか?
名前空間std
*にspecializationsを追加することを明示的に許可および推奨します。ハッシュ関数を追加する正しい(そして基本的にのみの)方法はこれです:
namespace std {
template <> struct hash<Foo>
{
size_t operator()(const Foo & x) const
{
/* your code here, e.g. "return hash<int>()(x.value);" */
}
};
}
(サポートを検討する可能性のある他の一般的な専門分野はstd::less
、std::equal_to
およびstd::swap
。)
*)関係するタイプの1つがユーザー定義である限り、私は思う。
私の賭けは、unordered_map/unorder_set/...クラスのハッシュテンプレート引数になります。
_#include <unordered_set>
#include <functional>
struct X
{
int x, y;
std::size_t gethash() const { return (x*39)^y; }
};
typedef std::unordered_set<X, std::size_t(*)(const X&)> Xunset;
typedef std::unordered_set<X, std::function<std::size_t(const X&)> > Xunset2;
int main()
{
auto hashX = [](const X&x) { return x.gethash(); };
Xunset my_set (0, hashX);
Xunset2 my_set2(0, hashX); // if you prefer a more flexible set typedef
}
_
もちろん
struct Xhasher { size_t operator(const X&) const; };
)std::hash<X>()
@Kerrek SBは1)および3)をカバーしています。
2)g ++とVC10は異なるシグネチャでstd::hash<T>::operator()
を宣言しますが、両方のライブラリ実装は標準に準拠しています。
標準では、std::hash<T>
のメンバーは指定されていません。このような特殊化はそれぞれ、std::unordered_set
の2番目のテンプレート引数に必要なものと同じ「ハッシュ」要件を満たさなければならないというだけです。すなわち:
H
は、少なくとも1つの引数型Key
を持つ関数オブジェクトです。H
は、コピー構築可能です。H
は破壊可能です。h
がH
またはconst H
型の式であり、k
が(おそらくconst
)Key
に変換可能な型の式である場合、h(k)
は、タイプsize_t
の有効な式です。h
がH
またはconst H
型の式であり、u
がKey
型の左辺値である場合、h(u)
は型を持つ有効な式ですu
を変更しないsize_t
。