为什么std中没有对const std::string进行特化的std::hash?

5

为什么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

这是有什么原因吗?

1个回答

5
为什么 std::hash 没有在 std 中被特化?
实际上,std没有特化任何 std::hash。原因可能是不需要特化。对于任何std::hash,它唯一拥有的函数是一个operator(),它以const T&为参数。因此,即使std::hash被特化,它也与std::hash完全相同。
然后回到您烦恼的代码,实际上应该这样:
std::unordered_map<std::string, int> m;

尽管 key_typestd::string,但实际上键的类型是 const std::string,可以通过 decltype(m)::value_type::first_type 访问。


更新:

当你考虑哈希的概念时,键应该不会被更改,因此 std::hash 的特化看起来比 std::hash 更合适。你同意吗?

确保散列表函数不会且不应该更改密钥,但同时,它可能不应该复制,那为什么不使用 std::hash<const T&>

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

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


你提出了一个有趣的观点,但它并没有回答问题。类型 T 总是可以隐式转换为 const T,但反过来则不成立。 - Mark Ransom
当你考虑哈希的概念时,关键字不应该被更改,因此std::hash<const T>的特化看起来比std::hash<T>更合适。你同意吗? - myoldgrandpa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接