5

Basically my question is, why won't this compile?

#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;


int main() {
    vector<int> v{1,2,3};
    auto hash_function=[](const vector<int>& v){
        size_t hash;
        for (int i = 0; i < v.size(); ++i) {
            hash+=v[i]+31*hash;
        }
        return hash;
        };

unordered_set<vector<int>, decltype(hash_function)> s(hash_function);
std::cout<<s.bucket_count();
std::cout<<"here";


}

but if I change the unordered_set line to this

unordered_set<vector<int>, decltype(hash_function)> s(10,hash_function);

It will. Why does it need an initial bucket count? It just seems bizarre that using a lambda forces me to add an initial bucket count, but using a functor it won't. See example here: C++ unordered_set of vectors for proof the functor version doesn't need an initial number of buckets.

Hisham Hijjawi
  • 1,803
  • 2
  • 17
  • 27
  • 1
    I'm a bit confused. Which constructor from http://www.cplusplus.com/reference/unordered_set/unordered_set/unordered_set/ are you trying to use? – Jerry Jeremiah Mar 11 '20 at 03:29
  • In other words, if the standard chose to support all combinations of arguments (default/iterator-pair/initializer_list * optional count/hash/equal/alloc), that would be 48 constructors (fewer with default arguments) and could cause ambiguity among the different function objects in overload resolution. So the standard chose to limit the form of constructors instead. – L. F. Mar 11 '20 at 03:38
  • @L.F. that comment makes a lot of sense. I always wondered why so many constructors were "missing", but after reading you're right it would cause the number of constructors to increase very quickly. – Hisham Hijjawi Mar 11 '20 at 03:47

2 Answers2

4

Just as a sidenote, if you have access to C++20 you can do the decltype for the lambda without constructing one, letting the std::unordered_set default construct it.

using hash_function = decltype([](const std::vector<int>& v) {
    size_t hash = 0;
    for (int i = 0; i < v.size(); ++i) {
        hash += v[i] + 31 * hash;
    }
    return hash;
});

std::unordered_set<std::vector<int>, hash_function> s();
MaLarsson
  • 260
  • 3
  • 10
3

That's simply because there is no such constructor.

The only unordered_set constructor that takes one parameter is the one that takes an instance of a custom allocator, and not a custom hash function.

P.S. You fail to initialize hash to 0, in your custom hash function. This carries an elevated risk of nasal demons. You should fix that.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148