gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-28 01:26:35 25 4
gpt4 key购买 nike

简介

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

问题

现在的问题是当我尝试用 boost::unordered_set::insert 插入一个点时我得到一个pair<iterator, bool>其中第一个成员是插入或原始条目的不可变迭代器,第二个成员是 bool。指示值是否已插入。不幸的是,我不能用不可变的迭代器改变值,所以我不得不想一些不同的东西。所以我现在尝试在集合中存储一个指向我的对象的指针,然后通过这个指针访问它以更改值(这应该没问题,因为该值与哈希值无关,因此不会改变 key )。所以我试图重载 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;
}

但是 unordered_set似乎没有使用我的重载函数(我尝试在最后打印种子但它没有显示因此我假设它使用不同的重载)即使我用 unordered_set< A *, boost::hash<A *> > 初始化我的集合.对于散列方面:当我尝试在没有指针的情况下使用集合时,它工作正常但我无法更改值。

可能的问题

我在 boost::hash reference 搜索了一下并发现这个重载 template<typename T> std::size_t hash_value(T* const&);我认为它被用来代替我自己的(并且只是用对象地址散列)但后来我想知道为什么我的编译器不提示重新定义这个函数(我编译时启用了 -Wall -Wextra -pedantic 标志。

问题

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

代码

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

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

using boost::unordered_set;

struct A {
double a;
double b;
bool isDup;
A(const double a, const double b): a(a), b(b), isDup(false) {}
A(const A & a): a(a.a), b(a.b), isDup(a.isDup) {}

/* Two equal As ought to have a bitwise equal floating point value so this is okay */
bool operator==(const A & a) const {
if (a.a != this->a) return false;
if (a.b != this->b) return false;
return true;
}
};


size_t hash_value(const 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;
}


int main() {
A a1(1.2, 2.3);
A a2(2.3, 3.4);
A a3(3.4, 4.5);
A a4(a1);

unordered_set< A *, boost::hash<A *> > usa; /* This was unintended lol */
if ( ! usa.insert(&a1).second ) std::cout << "Error " << a1.a << ", " << a1.b << " is already in set" << std::endl;
if ( ! usa.insert(&a2).second ) std::cout << "Error " << a2.a << ", " << a2.b << " is already in set" << std::endl;
if ( ! usa.insert(&a3).second ) std::cout << "Error " << a3.a << ", " << a3.b << " is already in set" << std::endl;
if ( ! usa.insert(&a4).second ) {
/* This is not called */
std::cout << "Error " << a4.a << ", " << a4.b << " is already in set" << std::endl;
(*(usa.insert(&a4).first))->isDup = true;
}
}

最佳答案

您的原始函数有几个问题 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::hash 的设计和 std::hash在组合多个成员的散列方面不太理想。我极力推荐使用来自 N3980 Types Don't Know # 的新哈希框架.

关于c++ - 为自定义对象指针重载 boost::hash_value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53484728/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com