在 std::unordered_set<std::unique_ptr> 中查找指针 T* (C++20)

Find a pointer T* in std::unordered_set<std::unique_ptr> (C++20)

正如Using a std::unordered_set of std::unique_ptr中指出的,在std::unordered_set<std::unique_ptr<T>>中找到一个指针T*并不容易。在 C++20 之前,我们被迫构造一个 std::unique_ptr<T>.

的实例

感谢 无序容器的异构查找 提议 (http://wg21.link/P0919r3 and http://wg21.link/p1690r1),这个问题在 C++20 中得到了解决。但是可用的解决方案对我来说看起来很笨拙(即使按照 C++ 标准)。看来我需要从头开始实现,而不是一个,而是两个仿函数(用于透明散列和透明比较):

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>>;

演示:https://gcc.godbolt.org/z/bqx714(该提案目前仅在 MSVC 中实现)。

这可行,但看起来像很多样板文件。我错过了什么吗?有没有办法使用 IDK 也许是一些标准的透明散列器或相等比较器?我看到 std::equal_to<void> 是透明的,但我不能直接使用它。也许有一种偷偷摸摸的方式来定义 unique_ptr<T> -> T* 隐式转换“只是为了这个 UnorderedSetOfUniquePtrs class”?欢迎提出您的想法。

您可以将冗长的内容转换为 std::to_address(感谢 @Caleth 指出)和现有的 std::hash,它专用于 std::unique_ptr 到 return基于原始地址的散列(感谢@Mikhail 的提示)。然后,使用成员函数模板实现散列和相等类型(注意您不再需要类型本身是模板):

struct Equal {
    using is_transparent = void;
    template<class U, class S>
    bool operator()(const U& lhs, const S& rhs) const { 
        return std::to_address(lhs) == std::to_address(rhs); 
    }
};

struct Hash {
    using is_transparent = void;
    template<class U>
    size_t operator()(const U& ptr) const {
        return std::hash<U>{}();
    }
}