在std :: unordered_set <std :: unique_ptr>C ++ 20

问题描述

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

由于对无序容器进行了异构查找提案(http://wg21.link/P0919r3http://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类”?欢迎您提出您的想法。

解决方法

您可以将详细程度更改为std::to_address(感谢@Caleth指出)和现有的std::hash,后者专门用于std::unique_ptr以基于原始返回哈希地址(感谢@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>{}();
    }
}