unordered_set from own type by overloading operator() fails

What’s wrong with the operator() inside Entity (hasher) ?

Copy-pasting it to a separate struct works :

#include <bitset>
#include <unordered_map>
using namespace std;

struct Entity {
  
  string name;
  
  size_t operator()(const Entity& k) const noexcept 
  { return std::hash<string>{}(k.name); }
  
  bool operator== (const Entity& e) const noexcept 
  { return e.name == name; }

};

struct KeyHasher {
  size_t operator()(const Entity& k) const noexcept
  { return std::hash<string>{}(k.name); }
};

int main(){
 // unordered_map<const Entity, bitset<24>, KeyHasher> m1; // OK
 unordered_map<const Entity, bitset<24>> m2; // unordered_map() ill-formed ?
  return 0;
}

Error :

<source>: In function 'int main()':
<source>:25:43: error: use of deleted function 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() 
[with _Key = const Entity; _Tp = std::bitset<24>; _Hash = std::hash<const Entity>; _Pred = std::equal_to<const Entity>; _Alloc = std::allocator<std::pair<const Entity, std::bitset<24> > >]'
   25 |   unordered_map<const Entity, bitset<24>> m2;
      |                                           ^~
In file included from /opt/compiler-explorer/gcc-cxx-modules-trunk-20220427/include/c++/11.0.0/unordered_map:47,
                 from <source>:3:
/opt/compiler-explorer/gcc-cxx-modules-trunk-20220427/include/c++/11.0.0/bits/unordered_map.h:141:7: note: 'std::unordered_map<_Key, _Tp, _Hash, _Pred, _Alloc>::unordered_map() [with _Key = const Entity; _Tp = std::bitset<24>; _Hash = std::hash<const Entity>; _Pred = std::equal_to<const Entity>; _Alloc = std::allocator<std::pair<const Entity, std::bitset<24> > >]'
 is implicitly deleted because the default definition would be ill-formed:
  141 |       unordered_map() = default;

run

>Solution :

If you don’t specify a hash function for your map it defaults to std::hash<Key> with your key type.
So you will need to define this specialization of std::hash

template<>
struct std::hash<const Entity>
{
    std::size_t operator()(const Entity const& k) const noexcept
    {
        return std::hash<string>{}(k.name);
    }
}

Leave a Reply