只要我能为我的类型提供一个hasher函数,为什么我需要专门化我的类型的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";
}
  • 如果我运行程序,程序会编译并正常工作。正如你所看到的,我的hasher函数的作用与调用运算符中的作用相同——std::hash<Foo>的专门化的成员函数,那么为什么我专门化后一个std::hash,而可以提供简单的散列函数呢?

  • 这是为了灵活性吗?例如,为我的Foo类型提供hasher函数而不是专门化std::hash需要被指定为模板参数和像unordered_set这样的关联容器实例化中的函数参数,而后者不必是例如?

只要我能为我的类类型提供哈希器,为什么我要[我需要]专门化std::hash<my_class_type>

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

  • 如果您的class是API的一部分(内部或外部无关紧要(,并且您希望为class的用户提供将其用作无序容器中的密钥的可能性(或出于任何其他原因,对其进行哈希(,则友好的方法是专门化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;
};
}

这是为了灵活性吗?

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

最新更新