Search code examples
c++boost

How to using boost::unordered_set with custom class?


I'm having a hard time calling hash_value. From this post, I want to apply to vector<vector<E>> where E is a custom object. My codes as follows:

struct E;
class myclass {
private:
     vector<E> lhs;
public:
    myclass(const vector<E>& v) :lhs{ v } {  };
    static size_t hash_value(const vector<E>& v) {
      size_t seed = 0;
         boost::hash_combine(seed, d.name);
         boost::hash_combine(seed, d.scope);
      return seed;
    }
    bool operator==(const vector<E> >& rhs) {
       for (unsigned i = 0; i < lhs.size(); i++)
         if (lhs[i].name != rhs[i].name || lhs[i].scope!= rhs[i].scope)
             return false;
       return true;
    };
};

then i call this code:

void test(std::vector<std::vector<E>>& A)
{
    boost::unordered_set < myclass > input_records(A.size());
    
    for (BOOST_AUTO(it, A.begin()); it != (A.end());) {
      auto k = input_records.insert(myclass{*it}); <<--
      ....
    }
}

however i get an error:

enter image description here

Also, in some cases this code executes but hash_value is never called. I'm not sure what am I missing?

How do I fix this?


Solution

  • You are trying to use boost::unordered_set<myclass>, which will internally use boost::hash<myclass>, which will look for a hash_value(myclass) function in the same namespace as myclass via Argument-Dependent Lookup. You made your hash_value() be a non-static member of myclass, so boost::hash will not be able to find it. But even if it could, it expects your hash_value() to take a single myclass object as a parameter, not a vector.

    See Extending boost::hash for a custom data type in Boost's documentation.

    Also, a class's operator== compares *this to another object. Inside of myclass, your operator== should take a single myclass object as a parameter, not a vector.

    Try this instead:

    struct E {
        string name;
        int scope;
    };
    
    size_t hash_value(const E& obj) {
        std::size_t seed = 0;
        boost::hash_combine(seed, obj.name);
        boost::hash_combine(seed, obj.scope);
        return seed;
    }
    
    class myclass {
    private:
        vector<E> vec;
    public:
        myclass(const vector<E>& v) : vec(v) {}
    
        bool operator==(const myclass& rhs) const {
           // vector has its own operator== for comparing elements in its array...
           return vec == rhs.vec;
        }
    
        friend size_t hash_value(const myclass& obj) {
            return boost::hash_range(obj.vec.begin(), obj.vec.end());
        }
    };
    
    void test(std::vector<std::vector<E>>& A)
    {
        boost::unordered_set<myclass> input_records(A.size());
        
        for (BOOST_AUTO(it, A.begin()); it != (A.end());) {
          auto k = input_records.insert(*it);
          ...
        }
    }