【问题标题】:Problems when using unordered_set as the key of unordered_map, in C++在 C++ 中使用 unordered_set 作为 unordered_map 的键时的问题
【发布时间】:2016-07-28 04:42:11
【问题描述】:

原题有点长,这里简化一下。

我需要创建一组带有相关整数的字符串,比如说一个训练组。然后我需要创建许多培训组。我想在一个容器中管理所有培训组。所以我决定使用 boost::unordered_map,键是 std::unordered_set。因为,BOOST 具有标准 C++ 容器的哈希值。

简化代码如下:

#include <string>
#include <unordered_set>
#include <utility>
#include<boost/unordered_map.hpp>

using namespace std;

int main()
{
    boost::unordered_map< unordered_set<string>, int> training_groups;
    pair<unordered_set<string>, int> a_training_group;
    training_groups.insert(a_training_group);
    return 0;
}

但是,代码没有编译成功。有许多神秘的警告和错误。错误如下:

1>C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xhash(30): error C2440: 'type cast' : cannot convert from 'const std::unordered_set<std::string,std::hash<_Kty>,std::equal_to<_Kty>,std::allocator<_Kty>>' to 'size_t'
1>          with
1>          [
1>              _Kty=std::string
1>          ]
1>          No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>          C:\Program Files\boost\boost_1_59_0\boost/functional/hash/extensions.hpp(262) : see reference to function template instantiation 'size_t stdext::hash_value<T>(const _Kty &)' being compiled
1>          with
1>          [
1>              T=std::unordered_set<std::string,std::hash<std::string>,std::equal_to<std::string>,std::allocator<std::string>>
1>  ,            _Kty=std::unordered_set<std::string,std::hash<std::string>,std::equal_to<std::string>,std::allocator<std::string>>
1>          ]

我不知道这个错误的根源在哪里以及如何解决它。如果编译器无法归档 unordered_set 的哈希函数,则错误信息将包含“Hash”或“Key”等字样。但是,它只是说明了类型转换,看起来类似于散列函数。所以,我感到很困惑。

谁能给点建议。我在 Windows 8 上使用 Visual Studio 2013。

PS:当我将 Key unordered_set&lt;string&gt; 更改为 set&lt;string&gt;vector&lt;string&gt; 时,程序编译成功。但是还是不知道是什么原因,如果我下定决心要用unordered_set&lt;string&gt;作为key,也不知道怎么解决。

【问题讨论】:

  • 为什么你认为集合必须是地图的关键?
  • 对于我真正的问题,训练组的第二部分实际上是另一个自定义类型的unordered_set。在这篇文章中,我使用整数来简化问题。所以,相比于自定义类型的 unordered_set,字符串的 unordered_set 更适合作为 Key。另外,我可以将 Key unordered_set 更改为 set 或 vector。但是,unordered_set 对于以后的操作更方便、更快捷。
  • @JohnSmith:使用unordered_set 作为键确实不是很快,因为比较谓词真的很慢。它可以是集合大小的二次方(正是因为集合是无序的)。

标签: c++ boost hash containers unordered


【解决方案1】:

Boost std::unordered_set 提供哈希函数,哈希函数列表包含例如一个std::set

http://www.boost.org/doc/libs/1_61_0/doc/html/hash/reference.html#idp6283424-bb

所以你必须提供自己的哈希函数,使用boost::hash_range时比较容易:

#include <string>
#include <unordered_set>
#include <utility>
#include <boost/functional/hash/hash_fwd.hpp>

namespace boost
{
template <class K, class C, class A>
std::size_t hash_value(const std::unordered_set<K, C, A>& v)
{
    return boost::hash_range(v.begin(), v.end());
}
} // namespace boost

#include <boost/functional/hash.hpp>
#include <boost/unordered_map.hpp>
int main()
{
    boost::unordered_map<std::unordered_set<std::string>, int> training_groups;
    std::pair<std::unordered_set<std::string>, int> a_training_group;
    training_groups.insert(a_training_group);
    return 0;
}

live example

【讨论】:

  • 非常感谢。我错过了 BOOST 没有为 std::unordered_set 提供哈希函数。顺便说一句,std::unordered_set 是否被视为标准 C++ 容器?
  • 是的,为 std::unordered_set 提供哈希函数很容易。一个有效的哈希函数有点棘手。为什么你认为 boost 没有提供一个?提示:您链接的页面说明了原因。
  • @JohnSmith: std::unordered_set 自 C++11 以来就是 C++ 标准库的一部分。
  • 您可能会遇到一个挑战,我不知道 boost::hash_range 的详细信息,但如果迭代顺序对于该哈希函数很重要,那么实际上可能会出现两个等效集具有不同的哈希值。从对文档的快速检查来看,它看起来与订单无关。
猜你喜欢
  • 2015-08-05
  • 1970-01-01
  • 2011-03-20
  • 2014-10-02
  • 2015-09-10
  • 2011-06-19
  • 2021-02-09
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多