Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/143.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ std::具有任意数量基本类型属性的对象的散列变体 讨论:_C++_C++11_Hash_Unordered Map_Stdhash - Fatal编程技术网

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;