Declaring hash function for unordered_set in c++? [duplicate]
Asked Answered
O

1

5

I have to use unordered_set for a rather large project, and to make sure I was using it correctly I tried a small example.

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

class Foo {
  private:
    int x;
  public:
    Foo(int in) {x = in;}
    bool operator==(const Foo& foo) const {return x == foo.x;}
    size_t hash(const Foo& foo) const {return x;}
};

int main() {
  Foo f1(3);
  unordered_set<Foo> s;
  s.insert(f1);
  return 0;
}

When I compile I get:

/tmp/cc3KFIf4.o: In function `std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_hash_code(Foo const&) const':
hashset.cc:(.text._ZNKSt8__detail15_Hash_code_baseI3FooS1_St9_IdentityIS1_ESt8equal_toIS1_ESt4hashIS1_ENS_18_Mod_range_hashingENS_20_Default_ranged_hashELb0EE12_M_hash_codeERKS1_[std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_hash_code(Foo const&) const]+0x19): undefined reference to `std::hash<Foo>::operator()(Foo) const'
/tmp/cc3KFIf4.o: In function `std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_bucket_index(std::__detail::_Hash_node<Foo, false> const*, unsigned int) const':
hashset.cc:(.text._ZNKSt8__detail15_Hash_code_baseI3FooS1_St9_IdentityIS1_ESt8equal_toIS1_ESt4hashIS1_ENS_18_Mod_range_hashingENS_20_Default_ranged_hashELb0EE15_M_bucket_indexEPKNS_10_Hash_nodeIS1_Lb0EEEj[std::__detail::_Hash_code_base<Foo, Foo, std::_Identity<Foo>, std::equal_to<Foo>, std::hash<Foo>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, false>::_M_bucket_index(std::__detail::_Hash_node<Foo, false> const*, unsigned int) const]+0x28): undefined reference to `std::hash<Foo>::operator()(Foo) const'
collect2: ld returned 1 exit status

It seems like it's not seeing my hash function, but I thought "hash" was the default function name. Did I define hash correctly? Or do I need to explicitly declare a separate hash class as the second template argument?

Orangewood answered 3/8, 2012 at 20:38 Comment(1)
The hash functionality is passed as an extra template parameter. You need (preferably) a functor and do unordered_set<Foo, FooHasher> s(FooHasher());Frayne
A
8

As an alternative to Xeo's suggestion in the comments, you can provide a specialization for std::hash before you instantiate the unordered_set.

namespace std {
    template <>
    struct hash<Foo> {
        size_t operator () (const Foo &f) const { return f.hash(f); }
    };
}

The foo parameter to your hash method seems extraneous to me, but I implemented the specialization to the interface you provided.

Adapter answered 3/8, 2012 at 21:4 Comment(2)
Ok thanks, that worked. I actually didn't for my hash function to take an extra parameter, that is a typo. It should be size_t hash() const {return x;} The only thing I'm confused about is why can't I just make a hash() like I did with operator==()? For operator== I didn't have to do anything extra.Orangewood
@user1575106: Different APIs will have different requirements. The standards writers cannot cater to everyone's desire, and the given interface makes it easy to try different hash algorithms without modifying the class.Adapter

© 2022 - 2024 — McMap. All rights reserved.