为自定义对象指针重载boost :: hash_value

时间:2018-11-26 15:51:13

标签: c++ boost hash hashset

简介

大家好,我尝试将boost::unordered_set用作自定义类类型。该类存储有关坐标和其他几个值的信息,但是仅使用坐标来创建哈希值。现在,如果我要插入一个点并且已经有一个坐标相等的点(因此有一个集合),我需要从原始对象中更改第三个值(例如object.isDuplicate = true 非常简化) 。请不要过于关注布尔值和原始代码中的重复检测原因,因为它有点复杂,但它只表明我需要对存储类的非常量访问。我只能使用boost 1.53和C ++ 03和GCC 4.4.3

问题

现在的问题是,当我尝试使用boost::unordered_set::insert插入点时,我得到一个pair<iterator, bool>,其中第一个成员是插入或原始条目的不变迭代器,第二个成员是{{ 1}},指示是否插入了该值。不幸的是,我无法使用不变的迭代器更改值,因此我不得不考虑一些不同的东西。因此,我现在尝试在集合中存储指向我的对象的指针,然后通过该指针访问它以更改值(这应该没关系,因为该值与哈希值无关,因此不会更改键)。因此,我尝试重载bool函数以接受指向此类的指针,如下所示:

boost::hash_value

但是size_t hash_value(const A * a) { size_t seed = 0; boost::hash_combine(seed, a->a); boost::hash_combine(seed, a->b); return seed; } 似乎没有使用我的重载函数(我尝试在最后打印种子,但是没有显示出来,因此我认为它使用了不同的重载),即使我使用{初始化了集合{1}}。对于哈希方面:当我尝试使用没有指针的集合时,它工作正常,但我无法更改该值。

可能的问题

我在boost::hash reference中进行了一些搜索,发现此重载unordered_set可以用来代替我自己的重载(并且只是使用对象地址进行哈希处理),但是我不知道为什么我的编译器不会提示重新定义此功能(我在启用unordered_set< A *, boost::hash<A *> >标志的情况下进行了编译。

问题

那么这是实际的问题吗?如果可以的话,我该如何告诉我的编译器明确使用我的自定义哈希函数?

代码

最后我写了一个小例子来测试一切

template<typename T> std::size_t hash_value(T* const&);

2 个答案:

答案 0 :(得分:2)

原始功能hash_value有几个问题:

  1. 它必须在boost命名空间中,因为boost::hash<T*>会调用boost::hash_value,这将禁用与参数有关的名称查找。
  2. 在模板中,名称查找执行了两次:在声明和实例化时。在实例化时,仅执行与参数相关的名称查找,但是被1禁用。这就是为什么必须在定义boost::hash之前(包括boost/hash.hpp之前)声明哈希函数的原因。

例如:

#include <cstddef> // std::size_t

struct A;
namespace boost { inline std::size_t hash_value(A* a); }

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

struct A { /*... */};

size_t boost::hash_value(A* a) {
    size_t seed = 0;
    boost::hash_combine(seed, a->a);
    boost::hash_combine(seed, a->b);
    std::cout << "Seed: " << seed << std::endl; /* This is not printed so i assume the function is not called */
    return seed;
}

此外,您需要指定自己的元素比较类,boost::unordered_set中的默认类比较指针。


请注意,boost::hashstd::hash的设计在组合多个成员的哈希值方面并不理想。对于N3980 Types Don't Know #中的新哈希框架,我不能推荐足够的东西。

答案 1 :(得分:0)

好吧,我现在自己找到了解决方案(或替代方法?)。第二个问题是boost::unordered_set默认使用的equal_to类。 equal_to<A *>永远不会返回false,因为我们总是有不同的点,因此&a1 == &a2总是会得出false,因此我也必须编写自己的比较器,该比较器在比较对象之前先取消引用对象,然后再进行比较唤起他们的operator==

然后,我将hash函数和比较器简单地封装在一个单独的类中,然后在创建这样的集合时将它们作为模板参数传递:

class compA {
public:
    size_t operator()(const A * a) const {
        size_t seed = 0;
        boost::hash_combine(seed, a->a);
        boost::hash_combine(seed, a->b);
        return seed;
    }

    bool operator()(const A * a1, const A * a2) const {
        if (*a1 == *a2) return true;
        return false;
    }
};

unordered_set<A *, compA, compA> usa;

但是我仍然想知道为什么我最初的尝试不起作用。