正如标题所说,std::begin
、std::end
、std::swap
等都是非常有名的std
“自定义点”(旨在由 ADL 找到的函数)。但是,我认为,std::hash
是唯一可由用户自定义的 std 行为,这意味着 (A) 打开 std
命名空间 (B) 创建部分特化。
为什么 std::hash
没有像其他点一样通过重载函数而不是部分特化类来设计为定制点?
最佳答案
您被一个常见的误解误导了,但是 std::hash
不是用户定义类型散列的自定义点。相反,std::hash
是标准容器使用的散列器的默认实现。如果您想使用具有用户定义类型的标准容器,那么您应该使用它们的模板参数来提供哈希器。
正确
所有需要对其内容使用哈希函数的标准容器都有一个模板参数,该参数接受一个函数对象,该函数对象的调用运算符计算哈希值。
#include <boost/functional/hash.hpp>
#include <unordered_set>
struct Point { int x, y; };
struct PointHasher {
size_t operator()(Point const &p) {
size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
};
int main() {
std::unordered_set<Point, PointHasher> m;
}
错误
写入 namespace std
通常是未定义的行为,另见 What are the reasons that extending the std namespace is considered undefined behavior?在某些情况下模板特化是一个异常(exception),但在这种情况下甚至没有必要。
#include <boost/functional/hash.hpp>
#include <unordered_set>
struct Point { int x, y; };
namespace std {
template<> struct hash<Point> {
size_t operator()(Point const &p) {
size_t seed = 0;
boost::hash_combine(seed, p.x);
boost::hash_combine(seed, p.y);
return seed;
}
};
}
int main() {
std::unordered_set<point> m;
}
关于c++ - 为什么 `std::hash` 不是通过重载为 `std::begin` 的自定义点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57838952/