Search code examples
c++hashc++11stdunordered-set

using lambda do define hash function throws exception


The following code defines a unordered_set. The code compiles just fine. But using the lambda function instead of functor throw when calling find:

libc++abi.dylib: terminate called throwing an exception

#include <unordered_set>

class pair_hash {
    public:
        size_t operator() (const std::pair<int, int> &x) const {
            return std::hash<int>()(x.first) ^ std::hash<int>()(x.second);
        }
};

int main() {
    std::unordered_set<std::pair<int, int>, pair_hash> temp;
    temp.find(std::make_pair(0,0));


    std::function<std::size_t(std::pair<int , int>)> fpair_hash;
    fpair_hash = [](const std::pair<int, int>& v) -> std::size_t
    {
        return std::hash<int>()(v.first) ^ std::hash<int>()(v.second);
    };

    std::unordered_set<std::pair<int, int>, decltype(fpair_hash)> temp2;
    //why does this not work?
    temp2.find(std::make_pair(0,0));
    return 0;
}

clang++ -std=c++11 -stdlib=libc++ -o test test.cpp


Solution

  • decltype(fpair_hash) is std::function<std::size_t(std::pair<int , int>)> so you are just building set with empty hash function.

    You need to provide your function to constructor of std::unordered_set:

    std::unordered_set<std::pair<int, int>, decltype(fpair_hash)> temp2(10, fpair_hash);
    

    This should make it work, but using std::function will have overhead of polymorphic call and you probably don't need it:

    auto fpair_hash = [](const std::pair<int, int>& v) -> std::size_t
    {
        return std::hash<int>()(v.first) ^ std::hash<int>()(v.second);
    };
    

    Finally, your hash function is not really good - it maps all pairs (x, x) to 0. Perhaps using something like x * 17 + y * 13 instead of x ^ y will reduce probability of collisions.