Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I specify a custom hash function explicitly for unordered_set by passing a named function?

Tags:

c++

c++11

hash

Based on the accepted answer to this question, one can use a specialization to std to provide a hash function for a user defined type.

#include <unordered_set>
#include <stdint.h>


struct FooBar {
    int i; 
};
namespace std {
    template <> struct hash<FooBar>
    {
        size_t operator()(const FooBar & x) const
        {
            return x.i;
        }
    };
}

int main(){
    std::unordered_set<FooBar> foo(0);
}

However, the documentation seems to imply that a custom hash function can also be passed explicitly into the constructor, and I would like to use a named function for this hash function.

However, my current attempt suffers from compile errors.

#include <unordered_set>
#include <stdint.h>

struct FooBar {
    int i; 
};

const size_t hashFooBar(const FooBar& foo) {
    return foo.i;
}

int main(){
    std::unordered_set<FooBar> foo(0, hashFooBar);
}

What is the correct template magic and method signature to make this work?

like image 799
merlin2011 Avatar asked Jan 24 '15 00:01

merlin2011


People also ask

How is unordered_set implemented in C++?

An unordered_set is implemented using a hash table where keys are hashed into indices of a hash table so that the insertion is always randomized.

What does unordered_set mean?

Unordered sets are containers that store unique elements in no particular order, and which allow for fast retrieval of individual elements based on their value. In an unordered_set, the value of an element is at the same time its key, that identifies it uniquely.

What is a hash function C++?

Working of the hash function in C++ with examples In C++, the hash function is a function where a key is pointing to a value which is an address; when this function is called, which uses the combination of letters and numbers in the hash table, which can be used for the arrangement of data.

Can we use pair in unordered_set?

We can use it to hash integers, floats, pointers, strings, arrays, pairs, and standard containers. That's all about using pair as a key in std::unordered_set in C++.


2 Answers

You need to supply the type of the hasher, which is in your case a function pointer. And your FooBar type must be equality comparable. Or equivalently you could supply a equality predicate in the same manner as supplying the hasher.

#include <unordered_set>
#include <stdint.h>

struct FooBar {
    int i; 
};

bool operator==(const FooBar& x, const FooBar& y)
{
    return x.i == y.i;
}

size_t hashFooBar(const FooBar& foo) {
    return foo.i;
}

int main(){
    std::unordered_set<FooBar, size_t(*)(const FooBar&)> foo(0, hashFooBar);
}

I should also note that it is more popular to supply a "functor" instead of a function, as the former can be inlined, while the latter is likely to not be inlined.

#include <unordered_set>
#include <stdint.h>

struct FooBar {
    int i; 
};

bool operator==(const FooBar& x, const FooBar& y)
{
    return x.i == y.i;
}

struct hashFooBar
{
    size_t operator()(const FooBar& foo) const {
        return foo.i;
    }
};

int main(){
    std::unordered_set<FooBar, hashFooBar> foo(0);
}
like image 75
Howard Hinnant Avatar answered Nov 14 '22 23:11

Howard Hinnant


In addition to Howard Hinnant's answer, which explains how to pass in both a function pointer and a custom preferred (the latter strictly preferred), you can also pass in a lambda like so:

bool operator==(const FooBar& x, const FooBar& y)
{
    return x.i == y.i;
}

int main() {
    auto hash = [](const FooBar& foo) { return foo.i; };
    std::unordered_set<FooBar, decltype(hash)> set{0, hash};
}

This will also likely inline the hash function, whereas the function pointer version definitely won't. You can also see that by just printing the sizes:

std::unordered_set<FooBar, decltype(hash)> setLambda{0, hash};
std::unordered_set<FooBar, int(*)(const FooBar&)> setFuncPtr{0, +hash};

std::cout << sizeof(setLambda);   // prints 56
std::cout << sizeof(setFuncPtr);  // prints 64, cause of the
                                  // extra function pointer
like image 25
Barry Avatar answered Nov 14 '22 21:11

Barry