Mr. Boy
Mr. Boy

Reputation: 63846

My class has a toString() method, how do I use this for hashing in std::unordered_set?

MyClass defines operator== and has a non-trivial internal state, but it does provide a wstring toString() method, which returns a serialized version of that state. So I thought it would be easy just to use toString() with hash<wstring> on std::unordered_set.

But is it possible to do this in a nice neat way without defining extraneous functor classes? I'm only just getting to grips with C++11 after moving to VS2013 and I thought this was one of the big steps forward, being able to define such things as lambdas?

Thanks for any suggestions how best to do this.

Upvotes: 1

Views: 179

Answers (2)

Casey
Casey

Reputation: 42594

The best approach is to tell std::hash how to hash MyClass via specialization:

namespace std {
template <>
struct hash<MyClass> {
  std::size_t operator () (const MyClass& mc) const {
    return std::hash<std::wstring>()(mc.toString());
  }
};
} // namespace std

so you don't need to bother with non-default template parameters for unordered_set or unordered_map.

Upvotes: 0

T.C.
T.C.

Reputation: 137404

auto hasher = [](const MyClass &m){ return std::hash<std::wstring>()(m.toString()); };
std::unordered_set<MyClass, decltype(hasher)> set(10, hasher);

Unfortunately this doesn't currently work with MSVC due to a bug.

Possible workarounds include writing a specialization of std::hash for MyClass, or storing the lambda in a std::function<std::size_t(const MyClass &)> and use that as the hasher's type:

std::function<std::size_t(const MyClass &)> hasher = 
                [](const MyClass &m) { return std::hash<std::wstring>()(m.toString()); };
std::unordered_set<MyClass, std::function<std::size_t(const MyClass &)>> set(10, hasher);

Upvotes: 3

Related Questions