首页 > 解决方案 > 只要我可以为我的类型提供哈希函数,为什么我需要为我的类型专门化 std::hash?

问题描述

只要我能提供我hasher的班级类型,我为什么要专攻std::hash<my_class_type>

我已经实现了这个例子:

class Foo;
template<>
class std::hash<Foo>;

class Foo
{
public:
    Foo(std::string const& s, int x) : str_(s), x_(x){}
    std::string str()const {return str_;}
    int get_x() const{ return x_;}

private:
    std::string str_;
    int x_{};
    friend bool operator==(Foo const&, Foo const&);
    friend class std::hash<Foo>;
};

bool operator==(Foo const& lhs, Foo const& rhs)
{
    return lhs.str_ == rhs.str_ && lhs.x_ == rhs.x_;
}

size_t hasher(Foo const& f)
{
    return std::hash<std::string>()(f.str()) ^
            std::hash<int>()(f.get_x());
}

namespace std
{
    template <>
    class hash<Foo>
    {
    public:
        using argument_type = Foo;
        using result_type = std::size_t;
        result_type operator()(argument_type const& a)const;
    };

    typename hash<Foo>::result_type
    hash<Foo>::operator()(argument_type const& a)const
    {
        return hash<std::string>()(a.str_) ^
                hash<int>()(a.x_);
    }
}

int main()
{

    std::unordered_set<Foo, decltype(hasher)*> u(5, hasher); // needs hasher as template argument and as function argument
    u.insert(Foo{"hi", 100});

    std::unordered_set<Foo> u2; // doesn't need either
    u2.insert(Foo("hi", 100));

    std::cout << "\ndone!\n";
}

标签: c++template-specialization

解决方案


只要我可以为我的班级类型提供我的哈希器,我为什么要[我需要]专攻std::hash<my_class_type>

不需要。无论如何,这里有一些这样做的原因:

  • 如果您class是 API 的一部分(内部或外部无关紧要),并且您应该为用户提供将class其用作无序容器中的Key的可能性(或出于任何其他原因,对其进行散列),则友好的做法是专业化std::hash。没有人会期望必须指定一个特殊的函数来为(可能记录为)可散列的类型进行散列。

  • 由于它的代码并不比编写实际的哈希算法(只是一个小样板)多多少,如果您要使用它不止一次或两次,您也可以为自己做这件事。它使代码更干净。

一旦你编写了特化,你就不需要自由散列函数,所以std::hash如果上述任何一个似乎适用,你可以立即特化(并完全跳过自由散列函数)。

使样板文件更短的一种方法是使用struct而不是class. 主要类模板是

namespace std {
    template<class Key>
    struct hash;
}

所以这样做也很有意义。您的定义将是:

namespace std {
    struct hash<Foo> {
        using argument_type = Foo;
        using result_type = std::size_t;
        result_type operator()(argument_type const& a) const;
    };
}

是为了灵活吗?

提供专业化不会影响灵活性,但它确实使它更易于使用。


推荐阅读