How to customize hash function for pair<int,int> in unordered_set using lambda expression

57 views Asked by At
int main(int argc, const char * argv[]) {
    function<bool(vector<int>&,vector<int>&)> cmp=[](vector<int>&a,vector<int>&b)->bool{
        return a[0]>b[0];
    };
    priority_queue<vector<int>,vector<vector<int>>,decltype(cmp)> q(cmp); //Fine

    
    
    function<size_t(pair<int, int>&)> pair_hash = [](pair<int, int>& p) -> size_t {
        return hash<int>()(p.first) ^ hash<int>()(p.second);
    };
    
    unordered_set<pair<int, int>, decltype(pair_hash)> blocks(pair_hash); //Error
}

I wonder why unordered_set can not use a lambda expression for a customized hash function.

At first I use this:

struct pair_hash {
    template <class T1, class T2>
    size_t operator () (pair<T1, T2> const &pair) const
    {
        size_t h1 = hash<T1>()(pair.first); 
        size_t h2 = hash<T2>()(pair.second);
        return h1 ^ h2;
    }
};

unordered_set<pair<int,int>, pair_hash> blocks; //Fine

The above code run well. So I wanted to convert it to a lambda expression. But I failed. I just want to know how to write a proper lambda expression about pair<int,int> hash function for unordered_set.

1

There are 1 answers

0
HarryP2023 On

So std::unordered_set does not have a matching constructor for what you are trying to do.

You need to add an additional argument to blocks to specify the size of the set, i.e. the bucket_count: https://en.cppreference.com/w/cpp/container/unordered_set/unordered_set

Like this:

std::unordered_set<std::pair<int, int>, decltype(pair_hash)> blocks(3, pair_hash);

Also, I don't think this is a lambda expression:

function<size_t(pair<int, int>&)> pair_hash = [](pair<int, int>& p) -> size_t {
    return hash<int>()(p.first) ^ hash<int>()(p.second);
};

You create a lambda expression, but then assign it to a std::function type object.

I wonder if this works instead:

auto pair_hash = [](pair<int, int>& p) -> size_t {
    return hash<int>()(p.first) ^ hash<int>()(p.second);
};

Additionally, this function is not the same, since it takes a const & as a parameter. Perhaps you need to add a const qualification to your lambda?:

size_t operator () (pair<T1, T2> const &pair) const
{
    size_t h1 = hash<T1>()(pair.first); 
    size_t h2 = hash<T2>()(pair.second);
    return h1 ^ h2;
}