Overloading boost::hash_value for custom object pointer
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;
}
}
c++ boost hash hashset
add a comment |
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;
}
}
c++ boost hash hashset
add a comment |
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;
}
}
c++ boost hash hashset
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;
}
}
c++ boost hash hashset
c++ boost hash hashset
asked Nov 26 '18 at 15:51
YastanubYastanub
578314
578314
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
There are a couple of issues with your original function hash_value
:
- It must be inside
boost
namespace becauseboost::hash<T*>
invokesboost::hash_value
which disables argument-dependent name lookup. - In templates name lookup is performed twice: at declaration and instantiation time. At instantiation time only argument-dependent name lookup is performed but it is disabled by 1. This is why your hash function must be declared before the definition of
boost::hash
(before includingboost/hash.hpp
).
E.g.:
#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;
}
Also, you need to specify your own element comparison class, the default one in boost::unordered_set
compares pointers.
As a side note the design of boost::hash
and std::hash
is less than ideal in respect of combining hashes of multiple members. I cannot recommend enough using the new hash framework from N3980 Types Don't Know #.
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function inboost
namespace and then created my set withunordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.
– Yastanub
Nov 26 '18 at 16:53
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
Sry it works now. I still hadboost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)
– Yastanub
Nov 26 '18 at 16:55
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally definedclass comparator
like i defined in my answer or can i just use the local class?
– Yastanub
Nov 26 '18 at 16:59
@Yastanub I do not like it either, and this is a part of the reason I don't usestd/boost::hash
. If you storeA
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.
– Maxim Egorushkin
Nov 26 '18 at 17:02
|
show 2 more comments
Okay i found a solution (or a workaround rather?) by myself now. A second problem was the equal_to
class which is used by default by boost::unordered_set
. equal_to<A *>
would never return false
because we always have distinct points and thus &a1 == &a2
would always evaluate to false so i had to write my own comparator as well which dereferences the objects before comparing them and then invoces their operator==
.
Then I simply encapsulated the hash
function and the comparator in a separate class and then pass them as template arguments when creating the set like this:
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;
But i still would like to know why my initial attempt did not work.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53484728%2foverloading-boosthash-value-for-custom-object-pointer%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
There are a couple of issues with your original function hash_value
:
- It must be inside
boost
namespace becauseboost::hash<T*>
invokesboost::hash_value
which disables argument-dependent name lookup. - In templates name lookup is performed twice: at declaration and instantiation time. At instantiation time only argument-dependent name lookup is performed but it is disabled by 1. This is why your hash function must be declared before the definition of
boost::hash
(before includingboost/hash.hpp
).
E.g.:
#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;
}
Also, you need to specify your own element comparison class, the default one in boost::unordered_set
compares pointers.
As a side note the design of boost::hash
and std::hash
is less than ideal in respect of combining hashes of multiple members. I cannot recommend enough using the new hash framework from N3980 Types Don't Know #.
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function inboost
namespace and then created my set withunordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.
– Yastanub
Nov 26 '18 at 16:53
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
Sry it works now. I still hadboost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)
– Yastanub
Nov 26 '18 at 16:55
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally definedclass comparator
like i defined in my answer or can i just use the local class?
– Yastanub
Nov 26 '18 at 16:59
@Yastanub I do not like it either, and this is a part of the reason I don't usestd/boost::hash
. If you storeA
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.
– Maxim Egorushkin
Nov 26 '18 at 17:02
|
show 2 more comments
There are a couple of issues with your original function hash_value
:
- It must be inside
boost
namespace becauseboost::hash<T*>
invokesboost::hash_value
which disables argument-dependent name lookup. - In templates name lookup is performed twice: at declaration and instantiation time. At instantiation time only argument-dependent name lookup is performed but it is disabled by 1. This is why your hash function must be declared before the definition of
boost::hash
(before includingboost/hash.hpp
).
E.g.:
#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;
}
Also, you need to specify your own element comparison class, the default one in boost::unordered_set
compares pointers.
As a side note the design of boost::hash
and std::hash
is less than ideal in respect of combining hashes of multiple members. I cannot recommend enough using the new hash framework from N3980 Types Don't Know #.
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function inboost
namespace and then created my set withunordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.
– Yastanub
Nov 26 '18 at 16:53
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
Sry it works now. I still hadboost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)
– Yastanub
Nov 26 '18 at 16:55
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally definedclass comparator
like i defined in my answer or can i just use the local class?
– Yastanub
Nov 26 '18 at 16:59
@Yastanub I do not like it either, and this is a part of the reason I don't usestd/boost::hash
. If you storeA
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.
– Maxim Egorushkin
Nov 26 '18 at 17:02
|
show 2 more comments
There are a couple of issues with your original function hash_value
:
- It must be inside
boost
namespace becauseboost::hash<T*>
invokesboost::hash_value
which disables argument-dependent name lookup. - In templates name lookup is performed twice: at declaration and instantiation time. At instantiation time only argument-dependent name lookup is performed but it is disabled by 1. This is why your hash function must be declared before the definition of
boost::hash
(before includingboost/hash.hpp
).
E.g.:
#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;
}
Also, you need to specify your own element comparison class, the default one in boost::unordered_set
compares pointers.
As a side note the design of boost::hash
and std::hash
is less than ideal in respect of combining hashes of multiple members. I cannot recommend enough using the new hash framework from N3980 Types Don't Know #.
There are a couple of issues with your original function hash_value
:
- It must be inside
boost
namespace becauseboost::hash<T*>
invokesboost::hash_value
which disables argument-dependent name lookup. - In templates name lookup is performed twice: at declaration and instantiation time. At instantiation time only argument-dependent name lookup is performed but it is disabled by 1. This is why your hash function must be declared before the definition of
boost::hash
(before includingboost/hash.hpp
).
E.g.:
#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;
}
Also, you need to specify your own element comparison class, the default one in boost::unordered_set
compares pointers.
As a side note the design of boost::hash
and std::hash
is less than ideal in respect of combining hashes of multiple members. I cannot recommend enough using the new hash framework from N3980 Types Don't Know #.
edited Nov 28 '18 at 10:24
answered Nov 26 '18 at 16:42
Maxim EgorushkinMaxim Egorushkin
87.7k11102186
87.7k11102186
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function inboost
namespace and then created my set withunordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.
– Yastanub
Nov 26 '18 at 16:53
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
Sry it works now. I still hadboost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)
– Yastanub
Nov 26 '18 at 16:55
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally definedclass comparator
like i defined in my answer or can i just use the local class?
– Yastanub
Nov 26 '18 at 16:59
@Yastanub I do not like it either, and this is a part of the reason I don't usestd/boost::hash
. If you storeA
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.
– Maxim Egorushkin
Nov 26 '18 at 17:02
|
show 2 more comments
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function inboost
namespace and then created my set withunordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.
– Yastanub
Nov 26 '18 at 16:53
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
Sry it works now. I still hadboost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)
– Yastanub
Nov 26 '18 at 16:55
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally definedclass comparator
like i defined in my answer or can i just use the local class?
– Yastanub
Nov 26 '18 at 16:59
@Yastanub I do not like it either, and this is a part of the reason I don't usestd/boost::hash
. If you storeA
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.
– Maxim Egorushkin
Nov 26 '18 at 17:02
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function in
boost
namespace and then created my set with unordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.– Yastanub
Nov 26 '18 at 16:53
Thanks i noticed the problem with the comparator too as stated in my own answer. But your solution does not seem to work for me as well. I declared the function in
boost
namespace and then created my set with unordered_set<A *, boost:.hash<A *>, compA> usa
but it does not work either. What do i have to pass for the second template argument? Also thanks for the link i will take a look at it.– Yastanub
Nov 26 '18 at 16:53
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
@Yastanub I compiled it and it works. What do you mean by does not work either?
– Maxim Egorushkin
Nov 26 '18 at 16:54
Sry it works now. I still had
boost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)– Yastanub
Nov 26 '18 at 16:55
Sry it works now. I still had
boost::hash_value(const A *)
as my signature when i make the parameter non const it works. Thanks alot :)– Yastanub
Nov 26 '18 at 16:55
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally defined
class comparator
like i defined in my answer or can i just use the local class?– Yastanub
Nov 26 '18 at 16:59
But i must say i do not really like this declaration very well because i only need the hash function in a single place inside one function. Is there an advantage over a locally defined
class comparator
like i defined in my answer or can i just use the local class?– Yastanub
Nov 26 '18 at 16:59
@Yastanub I do not like it either, and this is a part of the reason I don't use
std/boost::hash
. If you store A
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.– Maxim Egorushkin
Nov 26 '18 at 17:02
@Yastanub I do not like it either, and this is a part of the reason I don't use
std/boost::hash
. If you store A
by value that removes these problems for you. Or specify your custom comparison and hash classes, like you did.– Maxim Egorushkin
Nov 26 '18 at 17:02
|
show 2 more comments
Okay i found a solution (or a workaround rather?) by myself now. A second problem was the equal_to
class which is used by default by boost::unordered_set
. equal_to<A *>
would never return false
because we always have distinct points and thus &a1 == &a2
would always evaluate to false so i had to write my own comparator as well which dereferences the objects before comparing them and then invoces their operator==
.
Then I simply encapsulated the hash
function and the comparator in a separate class and then pass them as template arguments when creating the set like this:
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;
But i still would like to know why my initial attempt did not work.
add a comment |
Okay i found a solution (or a workaround rather?) by myself now. A second problem was the equal_to
class which is used by default by boost::unordered_set
. equal_to<A *>
would never return false
because we always have distinct points and thus &a1 == &a2
would always evaluate to false so i had to write my own comparator as well which dereferences the objects before comparing them and then invoces their operator==
.
Then I simply encapsulated the hash
function and the comparator in a separate class and then pass them as template arguments when creating the set like this:
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;
But i still would like to know why my initial attempt did not work.
add a comment |
Okay i found a solution (or a workaround rather?) by myself now. A second problem was the equal_to
class which is used by default by boost::unordered_set
. equal_to<A *>
would never return false
because we always have distinct points and thus &a1 == &a2
would always evaluate to false so i had to write my own comparator as well which dereferences the objects before comparing them and then invoces their operator==
.
Then I simply encapsulated the hash
function and the comparator in a separate class and then pass them as template arguments when creating the set like this:
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;
But i still would like to know why my initial attempt did not work.
Okay i found a solution (or a workaround rather?) by myself now. A second problem was the equal_to
class which is used by default by boost::unordered_set
. equal_to<A *>
would never return false
because we always have distinct points and thus &a1 == &a2
would always evaluate to false so i had to write my own comparator as well which dereferences the objects before comparing them and then invoces their operator==
.
Then I simply encapsulated the hash
function and the comparator in a separate class and then pass them as template arguments when creating the set like this:
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;
But i still would like to know why my initial attempt did not work.
answered Nov 26 '18 at 16:27
YastanubYastanub
578314
578314
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53484728%2foverloading-boosthash-value-for-custom-object-pointer%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown