C++ std::具有任意数量基本类型属性的对象的散列变体 讨论:
假设我有一个C++ std::具有任意数量基本类型属性的对象的散列变体 讨论:,c++,c++11,hash,unordered-map,stdhash,C++,C++11,Hash,Unordered Map,Stdhash,假设我有一个结构/类,它具有任意数量的属性,我想将这些属性用作std::无序映射的键,例如: struct Foo { int i; double d; char c; bool b; }; 我知道我必须为它定义一个hasher函子,例如: struct FooHasher { std::size_t operator()(Foo const &foo) const; }; 然后将我的std::无序\u映射定义为: std::unordered_ma
结构
/类
,它具有任意数量的属性,我想将这些属性用作std::无序映射的键
,例如:
struct Foo {
int i;
double d;
char c;
bool b;
};
我知道我必须为它定义一个hasher函子,例如:
struct FooHasher {
std::size_t operator()(Foo const &foo) const;
};
然后将我的std::无序\u映射定义为:
std::unordered_map<Foo, MyValueType, FooHasher> myMap;
我还看到了以下方案:
std::size_t operator()(Foo const &foo) const {
return std::hash<int>()(foo.i) ^
(std::hash<double>()(foo.d) << 1) ^
(std::hash<char>()(foo.c) >> 1) ^
(std::hash<bool>()(foo.b) << 1);
}
std::size\u t操作符()(Foo const&Foo)const{
返回std::hash()(foo.i)^
(std::hash()(foo.d)>1)^
(std::hash()(foo.b)一个简单的异或是对称的,当多次输入“相同”的值(hash(A)^hash(A)
为零)时,它的行为会很糟糕。有关详细信息,请参阅
这是组合哈希的问题。boost
有一个相当不错的哈希组合。编写一个哈希组合器,并使用它
没有解决这个问题的“官方方案”
我自己,我通常写一个超级哈希器,可以接受任何东西并对其进行哈希运算。它自动将元组、对和集合进行哈希运算,首先对集合中的元素计数进行哈希运算,然后对元素进行哈希运算
它首先通过ADL查找hash(t)
,如果失败,则检查它在助手名称空间(用于std
容器和类型)中是否有手动写入的哈希,如果失败,则执行std::hash{}(t)
然后,我对Foo
支持的哈希如下所示:
struct Foo {
int i;
double d;
char c;
bool b;
friend auto mytie(Foo const& f) {
return std::tie(f.i, f.d, f.c, f.b);
}
friend std::size_t hash(Foo const& f) {
return hasher::hash(mytie(f));
}
};
其中,我使用mytie
将Foo
移动到元组中,然后使用hasher::hash
的std::tuple
重载来获得结果
我喜欢结构相似类型的散列具有相同散列的想法。这让我在某些情况下表现得好像我的散列是透明的
请注意,以这种方式散列无序喵叫是个坏主意,因为无序喵叫的非对称散列可能会产生虚假的未命中
(Meow是map和set的通用名称。不要问我为什么:问。)标准哈希框架在组合哈希方面缺乏。使用xor
组合哈希是次优的
本文提出了一种更好的解决方案
其主要思想是使用相同的散列函数及其状态散列多个值/元素/成员
使用该框架,您的哈希函数将看起来:
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, Foo const& x) noexcept
{
using std::hash_append;
hash_append(h, x.i);
hash_append(h, x.d);
hash_append(h, x.c);
hash_append(h, x.b);
}
模板
void hash_append(HashAlgorithm&h,Foo const&x)noexcept
{
使用std::hash\u append;
hash_-append(h,x.i);
hash_-append(h,x.d);
hash_append(h,x.c);
hash_append(h,x.b);
}
和容器:
std::unordered_map<Foo, MyValueType, std::uhash<>> myMap;
std::无序映射myMap;
template <class HashAlgorithm>
void hash_append(HashAlgorithm& h, Foo const& x) noexcept
{
using std::hash_append;
hash_append(h, x.i);
hash_append(h, x.d);
hash_append(h, x.c);
hash_append(h, x.b);
}
std::unordered_map<Foo, MyValueType, std::uhash<>> myMap;