大家好,我尝试将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&);
答案 0 :(得分:2)
原始功能hash_value
有几个问题:
boost
命名空间中,因为boost::hash<T*>
会调用boost::hash_value
,这将禁用与参数有关的名称查找。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::hash
和std::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;
但是我仍然想知道为什么我最初的尝试不起作用。