C++ 只要我能为我的类型提供哈希函数,为什么我需要为我的类型专门化std::hash?

C++ 只要我能为我的类型提供哈希函数,为什么我需要为我的类型专门化std::hash?,c++,template-specialization,C++,Template Specialization,只要我能为我的类类型提供我的hasher,我为什么要专门化std::hash 我已经实现了这个示例: 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() cons

只要我能为我的类类型提供我的
hasher
,我为什么要专门化
std::hash

我已经实现了这个示例:

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";
}
Foo类;
模板
类std::hash;
福班
{
公众:
Foo(std::stringconst&s,intx):str_us,x_x{}
std::string str()常量{return str_;}
int get_x()常量{return x_;}
私人:
std::string str;
int x{};
友元布尔运算符==(Foo const&,Foo const&);
friend类std::hash;
};
布尔运算符==(Foo const&lhs、Foo const&rhs)
{
返回lhs.str==rhs.str&&lhs.x_==rhs.x;
}
大小散列器(Foo const&f)
{
返回std::hash()(f.str())^
std::hash()(f.get_x());
}
名称空间标准
{
模板
类散列
{
公众:
使用参数_type=Foo;
使用结果\u type=std::size\u t;
结果类型运算符()(参数类型常量&a)常量;
};
typename散列::结果类型
hash::operator()(参数类型常量&a)常量
{
返回hash()(a.str_389;)^
hash();
}
}
int main()
{
无序_集u(5,散列);//需要散列作为模板参数和函数参数
u、 插入(Foo{“hi”,100});
std::无序_集u2;//两者都不需要
u2.插入(Foo(“hi”,100));
标准::cout
只要我能为我的类类型提供hasher,为什么我[需要]专门化
std::hash

您不需要这样做。下面是一些这样做的原因:

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

  • 因为它的代码并不比编写实际的散列算法(只是一个小样板)多多少,所以如果你打算不止一次或两次地使用它,你也可以为了自己的利益而这样做。这样可以使代码更干净

一旦编写了专门化,您就不需要自由散列函数,因此如果上述任何一项适用,您可以立即专门化
std::hash
(并完全跳过自由散列函数)

使样板文件稍微短一点的一种方法是使用
struct
而不是
class
对其进行专门化

namespace std {
    template<class Key>
    struct hash;
}
名称空间std{
模板
结构散列;
}
所以这样做也很有意义。你的定义是:

namespace std {
    struct hash<Foo> {
        using argument_type = Foo;
        using result_type = std::size_t;
        result_type operator()(argument_type const& a) const;
    };
}
名称空间std{
结构散列{
使用参数_type=Foo;
使用结果\u type=std::size\u t;
结果类型运算符()(参数类型常量&a)常量;
};
}
这是为了灵活性吗

提供专门化不会影响灵活性,但会使其更易于使用。

您证明了您不需要专门化
std::hash
,那么您想问什么?为什么它也是一个选项?