c++ - 只要我可以为我的类型提供哈希函数,为什么我需要为我的类型专门化 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
而可以提供简单的哈希函数呢?是为了灵活吗?例如,提供一个
hasher
函数而不是专门std::hash
针对我的Foo
类型需要指定为模板参数和关联容器实例化中的函数参数,unordered_set
例如后者不需要?
解决方案
只要我可以为我的班级类型提供我的哈希器,我为什么要[我需要]专攻
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;
};
}
是为了灵活吗?
提供专业化不会影响灵活性,但它确实使它更易于使用。
推荐阅读
- ios - iOS 13.4 上未更改的 barTintColor UINavigationBar
- reactjs - 避免表单被重置
- java - 如何打开像谷歌应用广告这样的应用安装页面
- php - 我不能在我的 $_SESSION['car'] 数组中添加多个对象
- excel - 如何在 Excel 单元格中使用 OR 和 AND 执行 IF?
- r - 如何通过用户选择对数据进行子集化以在 R 闪亮的应用程序中绘图
- jqassistant - 如何使用 jqassistant 检测/解决超级方法调用
- python - 任何统计测试来了解数据 - 更高的价格是否会带来更好的质量?
- python - ValueError: `generator` 产生了一个形状为 (2, 200, 200, 3) 的元素,其中需要一个形状为 (4, 200, 200, 3) 的元素
- javascript - 如何根据 id 隔离对象?