为什么 std::hash<const std::string> 不专门用于 std?

myo*_*dpa 5 c++ hash

为什么不std::hash<const std::string>专门研究std?

它会导致编译错误,例如

std::unordered_map<const std::string, int> m;
m.insert(std::make_pair("Foo", 1)); //error
m["Bar"] = 2; // also error
Run Code Online (Sandbox Code Playgroud)

这有什么原因吗?

Ran*_*tep 5

为什么不std::hash<const std::string>专门研究std?

事实上,std 并没有专门化任何std::hash<const T>. 原因可能是不需要。对于 any std::hash<T>,它唯一具有的函数是 an operator(),它接受const T&作为它的参数。所以即使std::hash<const Foo>是专门化的,它也会和 完全一样std::hash<Foo>

然后回到您遇到麻烦的代码,它实际上应该是:

std::unordered_map<std::string, int> m;
Run Code Online (Sandbox Code Playgroud)

在这里,尽管是key_typeis std::string,但键的实际类型实际上是const std::string,可以使用 访问decltype(m)::value_type::first_type


更新:

当您想到哈希的概念时,不应更改键,因此 std::hash 的规范化看起来比 std::hash 更合适。你不同意吗?

当然,哈希函数不会也不应该更改密钥,但同时,它可能不应该复制,所以为什么不去呢std::hash<const T&>

需要注意的一件事是,专门化的类型并不总是等于参数类型。模板参数更多的是关于哈希函数与什么类型相关,而不是传递给调用运算符的类型。同样,numeric_limits<T>预期非 cv 限定的数字类型为 type T。这并不意味着const intconst double没有各自的限制。除非您期望 和 上有不同的行为hash<T>hash<const T>否则为什么要对它们进行专门化两次?

另一件需要注意的事情是,它std::hash实际上更像是与unordered_XXX系列捆绑在一起的实用程序类,并且主要用作默认无序系列的哈希函数,或者用于为要提供给的自定义类型定义自定义哈希函数无秩序的家庭。