As pointed out in Using a std::unordered_set of std::unique_ptr, it is not easy to find a pointer T*
in std::unordered_set<std::unique_ptr<T>>
. Prior to C++20 we were forced to construct an instance of std::unique_ptr<T>
.
Thanks to the Heterogeneous lookup for unordered containers proposals (http://wg21.link/P0919r3 and http://wg21.link/p1690r1), this problem is solved in C++20. But the available solution looks quite clumsy to me (even by C++ standards). It seems like I need to implement from scratch not one, but two functors (for transparent hashing and for transparent comparison):
template<class T>
struct Equal {
using is_transparent = void;
bool operator()(const std::unique_ptr<T>& lhs, const std::unique_ptr<T>& rhs) const {
return lhs == rhs;
}
bool operator()(const std::unique_ptr<T>& lhs, const T* rhs) const {
return lhs.get() == rhs;
}
bool operator()(const T* lhs, const std::unique_ptr<T>& rhs) const {
return lhs == rhs.get();
}
};
template<class T>
struct Hash {
using is_transparent = void;
size_t operator()(const std::unique_ptr<T>& ptr) const {
return std::hash<const T*>()(ptr.get());
}
size_t operator()(const T* ptr) const {
return std::hash<const T*>()(ptr);
}
};
template<class T>
using UnorderedSetOfUniquePtrs = std::unordered_set<std::unique_ptr<T>, Hash<T>, Equal<T>>;
Demo: https://gcc.godbolt.org/z/bqx714 (the proposal is currently implemented only in MSVC).
This works but looks like A LOT of boilerplate. Am I missing something? Is there a way to use IDK maybe some standard transparent hasher or equality comparator? I see that std::equal_to<void>
is transparent, but I cannot use it directly. Maybe there is a sneaky way to define unique_ptr<T> -> T*
implicit conversion "just for this UnorderedSetOfUniquePtrs
class"? Your ideas are welcomed.
ptr
for thehash
call – Vedavedalia