为什么 std::hash<const std::string> 不专攻 std?

Why isn't std::hash<const std::string> specialized in std?

为什么 std::hash<const std::string> 不专攻性病?

它会导致像

这样的编译错误
std::unordered_map<const std::string, int> m;
m.insert(std::make_pair("Foo", 1)); //error
m["Bar"] = 2; // also error

有什么原因吗?

Why isn't std::hash<const std::string> specialized in std?

事实上,std 没有特化任何 std::hash<const T>。原因可能是不需要。对于任何 std::hash<T>,它唯一的功能是一个 operator(),它将 const T& 作为参数。因此,即使 std::hash<const Foo> 被专门化,它也将与 std::hash<Foo>.

完全相同

然后回到你遇到麻烦的代码,它真的应该是:

std::unordered_map<std::string, int> m;

这里,虽然key_typestd::string,但是key的实际类型其实是const std::string,可以用decltype(m)::value_type::first_type.[=33=访问]


更新:

When you think of concept of hash, the key should not be changed, so specilaization of std::hash looks more appropriate than std::hash. Don't you agree ?

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

需要注意的一件事是,被特化的类型并不总是等于参数类型。模板参数更多的是关于散列函数与什么类型相关,而不是传递给调用运算符的是什么。类似地,numeric_limits<T> 期望一个非 cv 限定的数字类型作为类型 T。这并不意味着 const intconst double 没有各自的限制。除非您期望在 hash<T>hash<const T> 上有不同的行为,否则为什么要将它们特化两次?

还有一件事要注意,std::hash 实际上更像是一个与 unordered_XXX 系列捆绑在一起的实用程序 class,主要用作无序的哈希函数family 默认情况下,或用于为要提供给无序系列的自定义类型定义自定义哈希函数。