c++ - 为什么 `std::hash` 不是通过重载为 `std::begin` 的自定义点?

标签 c++ hash overloading partial-specialization customization-point

正如标题所说,std::beginstd::endstd::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/

相关文章:

perl - 如何取消引用从类的方法返回的哈希?

python - 用于更快的 Python 字典查找的预哈希字符串键?

c++ - 是否可以在不复制的情况下向下转换shared_ptr?

c++ - 将 UTF-16(Windows 上的 wchar_t)转换为 UTF32

javascript - 在链接中使用 # 而不是 GET params = 更快?

C++ 重载函数和错误

c++ - unique_ptrs 的循环 vector 并为运行时类型调用正确的重载

qt - 'QMessageBox::critical':4 个重载中没有一个可以转换所有参数类型

C++ curl : treating header and body data differently

c++ - 枚举、类、命名空间和长名称