Introduction
Hello everyone, i try to use boost::unordered_set
for a custom class type. The class stores information about coordinates and several other values but only the coordinates are used to create the hash value. Now if i want to insert a point and there is already a point with equal coordinates (hence a set) i need to change a third value from the original object (like object.isDuplicate = true
very simplified). Please do not stick too much to the bool value and duplicate detection cause in the original code it is a bit more complex but it should only show that i need a non-const access to the stored class. I can only use boost 1.53 and C++03 and GCC 4.4.3
The problem
The problem is now when i try to insert a point with boost::unordered_set::insert
i get a pair<iterator, bool>
of which the first member is an immutable iterator to the inserted or original entry and the second is a bool
indicating if the value was inserted or not. I can not change the value with an immutable iterator unfortunately so i had to think of something different. So i now try to store a pointer to my object in the set and then access it via this pointer to change the value (which should be okay since the value has nothing to do with the hash value and thus does not alter the key). So i tried to overload the boost::hash_value
function to accept a pointer to my class like this:
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;
}
But the unordered_set
does not seem to use my overloaded function (i tried printing the seed at the end but it does not show up hence i assume it uses a different overload) even if i initialize my set with unordered_set< A *, boost::hash<A *> >
. For the hashing aspect: when i try to use the set without a pointer it works fine but i can not alter the value.
Possible problem
I searched a bit around in the boost::hash reference and found this overload template<typename T> std::size_t hash_value(T* const&);
which i think is used instead of my own one (and simply hashes with the objects address) but then i wonder why my compiler does not prompt a redefinition of this function (i compile with -Wall -Wextra -pedantic
flags enabled.
Question
So is this the actual problem? And if it is how can i tell my compiler to explicitely use my custom hash function?
Code
At last a little example i wrote to test everything
#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;
}
}