Reputation: 63846
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
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
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