我的班级有一个 toString() 方法,我如何使用它在 std::unordered_set 中进行散列?
Posted
技术标签:
【中文标题】我的班级有一个 toString() 方法,我如何使用它在 std::unordered_set 中进行散列?【英文标题】:My class has a toString() method, how do I use this for hashing in std::unordered_set? 【发布时间】:2014-10-09 15:54:14 【问题描述】:MyClass
定义了operator==
并具有非平凡的内部状态,但它确实提供了一个wstring toString()
方法,该方法返回该状态的序列化版本。所以我认为在std::unordered_set
上使用toString()
和hash<wstring>
会很容易。
但是是否可以在不定义无关函子类的情况下以一种很好的方式做到这一点?在迁移到 VS2013 之后,我才刚刚开始掌握 C++11,我认为这是向前迈出的一大步,能够定义诸如 lambdas 之类的东西?
感谢任何建议如何最好地做到这一点。
【问题讨论】:
【参考方案1】:auto hasher = [](const MyClass &m) return std::hash<std::wstring>()(m.toString()); ;
std::unordered_set<MyClass, decltype(hasher)> set(10, hasher);
很遗憾,目前这不适用于 MSVC due to a bug。
可能的变通方法包括为MyClass
编写std::hash
的特化,或将lambda 存储在std::function<std::size_t(const MyClass &)>
中并将其用作哈希器的类型:
std::function<std::size_t(const MyClass &)> hasher =
[](const MyClass &m) return std::hash<std::wstring>()(m.toString()); ;
std::unordered_set<MyClass, std::function<std::size_t(const MyClass &)>> set(10, hasher);
【讨论】:
【参考方案2】:最好的方法是告诉std::hash
如何通过专门化来散列MyClass
:
namespace std
template <>
struct hash<MyClass>
std::size_t operator () (const MyClass& mc) const
return std::hash<std::wstring>()(mc.toString());
;
// namespace std
因此您无需为unordered_set
或unordered_map
的非默认模板参数操心。
【讨论】:
奇怪的是,std::hash
的专业化似乎需要提供result_type
和argument_type
类型定义,无论出于何种原因。此外,问题要求 lambdas。
@T.C.该问题要求“建议如何最好地做到这一点”。最好的方法是毫无疑问地告诉标准库如何散列自定义类型,这样就不需要特殊处理来声明或初始化 unordered_maps 和 unordered_sets。
@T.C. 17.6.3.4 中的 Hash 要求中没有 result_type
和 argument_type
意味着该要求是针对标准库提供的特化,可能是针对希望将它们作为 unary_functions 处理的用户。我发现很难相信有一个病态的实施,例如unordered_set 可以与任何 Hash 一起正常工作,但明确断言,当且仅当它是 std::hash
专业化时,它的 hasher 必须具有这些类型。
[unord.hash] 的最后一个项目符号特别免除了用户定义的特化-“满足表达式h(k)
的要求,其中h
是hash<Key>
和@987654335 类型的对象@ 是 Key
类型的对象,除非 hash<Key>
是一个用户定义的专业化,它依赖于至少一个用户定义的类型,否则不应抛出异常”,所以在我看来,其他要求适用于所有专业化,无论是由图书馆还是用户提供(尽管如果它确实提出了这样的要求,老实说,这听起来像是一个缺陷)。
您能解释一下为什么需要template<>
吗?我做了与这个答案非常相似的事情并且它有效,但我根本没有使用模板,例如struct hash std::size_t operator () (const MyClass& mc)... ;
以上是关于我的班级有一个 toString() 方法,我如何使用它在 std::unordered_set 中进行散列?的主要内容,如果未能解决你的问题,请参考以下文章