我必须制作一个由以下键和值组成的unordered_map:
key:unsigned char,unsigned char,unsigned char
value:structure(int,int)
以下是我定义的代码:
namespace G {
typedef std::tuple< unsigned char, unsigned char , unsigned char> key_t;
struct IndexGuide
{
int index;
int SerialNo;
};
typedef std::unordered_map<const key_t,IndexGuide> GuideDouble;
}
using namespace G;
这段代码有什么问题,因为当我在linux终端上链接这些文件时。它给了我错误。错误的一部分如下
在函数`std :: __ detail :: _ Hash_code_base const,std :: pair const,G :: IndexGuide&gt;中, std :: _ Select1st const,G :: IndexGuide&gt; &gt;中 的std :: equal_to const&gt;,std :: hash const&gt;,std :: __ detail :: _ Mod_range_hashing, 的std :: __细节:: _ Default_ranged_hash, false&gt; :: _ M_bucket_index(std :: __ detail :: _ Hash_node const,G :: IndexGuide&gt;,false&gt; const *,unsigned int)const':
答案 0 :(得分:2)
您必须提供一个哈希函数,告诉std::unordered_map
如何从key_t
生成哈希值。您可以通过hash
模板仿函数的专业化来实现:
提供密钥:
struct Key{
unsigned char first;
unsigned char second;
unsigned char third;
bool operator==(const Key &other) const {
return (first == other.first
&& second == other.second
&& third == other.third);
}
};
专门化哈希模板:
namespace std {
template <>
struct hash< Key>
{
std::size_t operator()(const Key& k) const
{
using std::hash;
// Compute individual hash values for first,
// second and third and combine them using XOR
// and bit shifting:
return ((hash<char>()( k.first)
^ (hash<char>()( k.second) << 1)) >> 1)
^ (hash<int>()( k.third) << 1);
}
};
}
std::unordered_map< Key, IndexGuide> myMap;
正如我在评论中所说,你可以看看at this SO thread。
答案 1 :(得分:2)
所以你的基本问题是你没有std::tuple
的哈希 - 标准库目前默认没有。我认为这是一种疏忽。
您无法为std::tuple
添加默认的哈希 - 无论是针对所有tuple
还是针对您的特定列表 - 因为标准规定您不允许:
17.6.4.2.1 命名空间std [namespace.std] / 1如果C ++程序添加了声明或定义,则它的行为是未定义的 命名空间std或命名空间std中的命名空间,除非另有说明 指定。程序可以为任何程序添加模板专业化 标准库模板到命名空间std只有声明 取决于用户定义的类型,专业化符合 原始模板的标准库要求,而不是 明确禁止。
因此,您可以为tuple
类型编写自定义哈希,并将其传递给unordered_map
,或使用不仅仅为std::tuple
的类型,或编写支持每个tuple
的自定义哈希(包括递归tuple
),同时还支持hash<T>
查找非tuple
s。第四个选项是编写自己的基于ADL的哈希系统并进行设置,以便具有有效std::hash
特化的类型使用该系统,以及其他各种后备。
我将说明上面的第3个选项。
首先,您希望能够以不会导致许多虚假冲突的方式组合两个哈希值。
inline std::size_t hash_result_combine(std::size_t lhs, std::size_t rhs)
{
return lhs ^( rhs + 0x9e3779b9 + (lhs<<6) + (lhs>>2));
}
这需要两个hash
输出,并将它们组合在一起。然后我们可以连续多次链接。 (从https://stackoverflow.com/a/7111460/1774667借来的常数)
接下来,一些索引样板。使用std::tuple
的大多数通用工作都需要这样的东西:
template<unsigned...>struct indexes{};
template<unsigned Max, unsigned... Is>struct make_indexes:make_indexes<Max-1,Max-1,Is...> {};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
最后,一个几乎适用于所有类型的哈希类:
struct my_hasher {
template<typename... Args>
std::size_t operator()(indexes<>, std::tuple<Args...> const& tup) const {
return 0;
}
template<unsigned I, unsigned... Is,typename... Args>
std::size_t operator()(indexes<I, Is...>,std::tuple<Args...> const& tup) const {
return hash_result_combine( (*this)(std::get<I>(tup)), (*this)(indexes<Is...>, tup) );
}
template<typename... Args>
std::size_t operator()(std::tuple<Args...> const& tup) const {
return (*this)(make_indexes<sizeof...(Args)>(), tup);
}
template<typename T>
std::size_t operator()(T const& t) const { return std::hash<T>()(t); }
};
您可以将my_hasher
传递给unordered_set
代替hash<T>
tuple
s,tuple
s包含元组,甚至是标量 - 它非常慷慨。
typedef std::unordered_map<const key_t,IndexGuide, my_hasher> GuideDouble;
现在我们正确哈希key_t
。
答案 2 :(得分:0)
unordered_set
为了对您定义的类型使用unordered_set
,您需要专门化该类型的hash<>
模板,如下所示:
namespace std {
template <> struct hash<key_t>
{
size_t operator()(const key_t & t) const
{
// the logic for hashing
}
};
}
答案 3 :(得分:0)
std :: tuple没有默认的哈希。
您可以使用此代码段Generic hash for tuples in unordered_map / unordered_set