以三个无符号字符为关键字的无序映射
Unordered Map with three unsigned chars as key
我必须制作一个由以下键和值组成的无序映射:
-
键:无符号字符、无符号字符和无符号字符
-
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>中,std::_Select 1st const,G::IndexGuide>>,std::equal_toconst>,std::hash const>,td::__detail::_Mod_range_hashing,std::__detail::_Default_ranged_hash,false>::_M_bucket_index(std::__detail::_Hash_node const,G::IndexGuide>,false>const*,unsigned int)const':
因此,您的基本问题是没有std::tuple
的哈希器——默认情况下,标准库当前没有哈希器。我认为这是一个疏忽。
您不能为std::tuple
添加默认哈希器——无论是为所有tuple
还是为您的特定列表——因为标准规定您不允许:
17.6.4.2.1命名空间std〔Namespace.std〕/1如果C++程序将声明或定义添加到命名空间std或命名空间std中的命名空间,除非另有说明指定。程序可以为任何仅当声明取决于用户定义的类型,并且专业化满足原始模板的标准库要求,而不是明确禁止。
因此,您要么为tuple
类型编写一个自定义哈希器,并将其传递给unordered_map
,要么为密钥使用一个不仅仅是std::tuple
的类型,或者编写一个自定义哈希器,支持每个tuple
(包括递归tuple
s),同时也支持非tuple
s的hash<T>
查找。第四种选择是编写自己的基于ADL的哈希系统,并对其进行设置,以便具有有效std::hash
专业化的类型使用该哈希系统,以及各种其他回退。
我将说明上面的第三个选项。
首先,您希望能够以一种不会导致许多虚假冲突的方式组合两个哈希值。
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...>{};
最后,一个几乎适用于所有类型的hasher类:
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); }
};
对于tuple
s、包含元组的tuple
s,甚至对于标量,可以将my_hasher
传递给unordered_set
来代替hash<T>
,这是非常慷慨的。
typedef std::unordered_map<const key_t,IndexGuide, my_hasher> GuideDouble;
现在我们对CCD_ 19进行适当的散列。
您必须提供一个散列函数,该函数告诉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);
}
};
specialized散列模板:
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;
正如我在评论中所说,你可以看看这个SO线程。
unordered_set
是使用哈希表实现的
为了将unordered_set
用于您定义的类型,您需要专门化该类型的hash<>
模板,如下所示:
namespace std {
template <> struct hash<key_t>
{
size_t operator()(const key_t & t) const
{
// the logic for hashing
}
};
}
std::tuple没有默认的hasher。
您可以使用以下代码片段Unrderede_map/undered_set 中元组的通用哈希
- Visual Studio 2015:Extern "C" 和 "export" 关键字
- C++中的"inline"关键字
- 如何确保C++函数在定义之前声明(如override关键字)
- 递归无序映射
- c++找不到具有相同哈希的无序集合元素
- 正在将无序映射设置为无序映射的值
- 智能指针作为无序映射键,并通过引用进行比较
- 谷歌模拟和覆盖关键字
- 结构体 S { int align; } 之间的区别;(struct 关键字后的名称)和 struct { int al
- 如果全局变量默认是外部变量,为什么要添加"extern"关键字?
- 如何使用set实现无序数据结构?
- 如何写向量的无序向量集,即unordered_set<向量<向量<int>>集合?
- 如何禁用 CPU 的无序执行
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 为什么"delete"关键字不删除节点?
- 在 c++ 中正确定义"this"关键字?
- 这个额外的关键字在这个 c++ 类声明中是什么意思?
- 以std::字符串作为关键字,按字典顺序对一个无序映射进行排序
- 以三个无符号字符为关键字的无序映射
- 包含一个图形节点作为关键字的无序映射