Overloading boost::hash_value for custom object pointer












0















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;
}
}









share|improve this question



























    0















    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;
    }
    }









    share|improve this question

























      0












      0








      0








      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;
      }
      }









      share|improve this question














      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






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Nov 26 '18 at 15:51









      YastanubYastanub

      578314




      578314
























          2 Answers
          2






          active

          oldest

          votes


















          2














          There are a couple of issues with your original function hash_value:




          1. It must be inside boost namespace because boost::hash<T*> invokes boost::hash_value which disables argument-dependent name lookup.

          2. 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 including boost/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 #.






          share|improve this answer


























          • 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











          • 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











          • @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





















          0














          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.






          share|improve this answer























            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
            });


            }
            });














            draft saved

            draft discarded


















            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









            2














            There are a couple of issues with your original function hash_value:




            1. It must be inside boost namespace because boost::hash<T*> invokes boost::hash_value which disables argument-dependent name lookup.

            2. 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 including boost/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 #.






            share|improve this answer


























            • 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











            • 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











            • @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


















            2














            There are a couple of issues with your original function hash_value:




            1. It must be inside boost namespace because boost::hash<T*> invokes boost::hash_value which disables argument-dependent name lookup.

            2. 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 including boost/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 #.






            share|improve this answer


























            • 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











            • 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











            • @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
















            2












            2








            2







            There are a couple of issues with your original function hash_value:




            1. It must be inside boost namespace because boost::hash<T*> invokes boost::hash_value which disables argument-dependent name lookup.

            2. 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 including boost/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 #.






            share|improve this answer















            There are a couple of issues with your original function hash_value:




            1. It must be inside boost namespace because boost::hash<T*> invokes boost::hash_value which disables argument-dependent name lookup.

            2. 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 including boost/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 #.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            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 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











            • 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











            • @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





















            • 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











            • 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











            • @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



















            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















            0














            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.






            share|improve this answer




























              0














              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.






              share|improve this answer


























                0












                0








                0







                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.






                share|improve this answer













                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.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 26 '18 at 16:27









                YastanubYastanub

                578314




                578314






























                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

                    Calculate evaluation metrics using cross_val_predict sklearn

                    Insert data from modal to MySQL (multiple modal on website)