如何将 std::hash::operator() 专门化为无序容器中的用户定义类型?
支持 std::unordered_set
和 std::unordered_map
中用户定义的键类型 必须提供 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;
仅编写 std::unordered_set
会更方便 具有类型 X
的默认哈希, 就像编译器和库附带的类型一样。 查阅
- C++ 标准 Draft N3242 § 20.8.12 [unord.hash] 和 §17.6.3.4 [hash.requirements],
- Boost.Unordered
- g++
include\c++\4.7。 0\bits\function_hash.h
- VC10
include\xfunction
- 各种Stack Overflow 中的相关问题
似乎可以专门化 std: :hash
:
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
?我对此百感交集。哪个
std::hash
版本(如果有)符合 C++11 标准?::operator() 是否有一种便携的方式来做到这一点?
To support user-defined key types in std::unordered_set<Key>
and std::unordered_map<Key, Value>
one has to provide operator==(Key, Key)
and a hash functor:
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;
It would be more convenient to write just std::unordered_set<X>
with a default hash for type X
,
like for types coming along with the compiler and library.
After consulting
- C++ Standard Draft N3242 §20.8.12 [unord.hash] and §17.6.3.4 [hash.requirements],
- Boost.Unordered
- g++
include\c++\4.7.0\bits\functional_hash.h
- VC10
include\xfunctional
- various related questions in Stack Overflow
it seems possible to specialize 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
}
Given compiler support for C++11 is yet experimental---I did not try Clang---, these are my questions:
Is it legal to add such a specialization to namespace
std
? I have mixed feelings about that.Which of the
std::hash<X>::operator()
versions, if any, is compliant with C++11 standard?Is there a portable way to do it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
明确允许并鼓励您将专业化添加到命名空间
std
*。添加哈希函数的正确(并且基本上是唯一)方法是这样的:(您可能考虑支持的其他流行专业化是
std::less
、std::equal_to
和std::swap
。)*)只要所涉及的类型之一是用户定义的,我想。
You are expressly allowed and encouraged to add specializations to namespace
std
*. The correct (and basically only) way to add a hash function is this:(Other popular specializations that you might consider supporting are
std::less
,std::equal_to
andstd::swap
.)*) as long as one of the involved types is user-defined, I suppose.
我的赌注是 unordered_map/unorder_set/... 类的 Hash 模板参数:
当然,
struct Xhasher { size_t operator(const X&) const; };
)std::hash()
-
My bet would be on the Hash template argument for the unordered_map/unorder_set/... classes:
Of course
struct Xhasher { size_t operator(const X&) const; };
)std::hash<X>()
-
@Kerrek SB 已涵盖 1) 和 3)。
2) 尽管 g++ 和 VC10 使用不同的签名声明 std::hash::operator() ,但这两个库实现都符合标准。
标准未指定
std::hash
的成员。它只是说每个这样的专业化必须满足 std::unordered_set 的第二个模板参数所需的相同“哈希”要求等等。即:H
是一个函数对象,至少有一个参数类型Key
。H
是可复制构造的。H
是可破坏的。h
是H
或const H
类型的表达式,并且k
是可转换为(可能是const
)Key
,则h(k)
是类型为size_t
的有效表达式。h
是H
或const H
类型的表达式,并且u
是类型的左值Key
,则h(u)
是类型为size_t
的有效表达式,不会修改u
。@Kerrek SB has covered 1) and 3).
2) Even though g++ and VC10 declare
std::hash<T>::operator()
with different signatures, both library implementations are Standard compliant.The Standard does not specify the members of
std::hash<T>
. It just says that each such specialization must satisfy the same "Hash" requirements needed for the second template argument ofstd::unordered_set
and so on. Namely:H
is a function object, with at least one argument typeKey
.H
is copy constructible.H
is destructible.h
is an expression of typeH
orconst H
, andk
is an expression of a type convertible to (possiblyconst
)Key
, thenh(k)
is a valid expression with typesize_t
.h
is an expression of typeH
orconst H
, andu
is an lvalue of typeKey
, thenh(u)
is a valid expression with typesize_t
which does not modifyu
.