【问题标题】:Why isn't std::hash<const std::string> specialized in std?为什么 std::hash<const std::string> 不专门用于 std?
【发布时间】:2021-12-31 06:09:45
【问题描述】:

为什么std::hash&lt;const std::string&gt; 不专攻std?

它会导致编译错误

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

这有什么原因吗?

【问题讨论】:

    标签: c++ hash


    【解决方案1】:

    为什么std::hash&lt;const std::string&gt; 不专攻std?

    事实上,std 没有专门化任何std::hash&lt;const T&gt;。原因可能是不需要它。对于任何std::hash&lt;T&gt;,它唯一的函数是operator(),它接受const T&amp; 作为它的参数。因此,即使std::hash&lt;const Foo&gt; 是特化的,它也将与std::hash&lt;Foo&gt; 完全相同。

    然后回到你所困扰的代码,它真的应该是:

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

    这里,尽管key_typestd::string,但是key的实际类型其实是const std::string,可以用decltype(m)::value_type::first_type访问。


    更新:

    当你想到散列的概念时,不应该改变键,所以 std::hash 的规范看起来比 std::hash 更合适。你不同意吗?

    确定哈希函数不会也不应该改变密钥,但同时它可能不应该复制,那么为什么不去std::hash&lt;const T&amp;&gt;呢?

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

    还有一点需要注意的是std::hash 实际上更像是一个与unordered_XXX 系列捆绑在一起的实用程序类,并且默认主要用作无序系列的散列函数,或用于定义您的自定义散列将自定义类型提供给无序族的函数。

    【讨论】:

    • 您提出了一个有趣的观点,但它没有回答问题。 T 类型始终可以隐式转换为 const T,但反过来则不然。
    • 当您想到哈希的概念时,不应该更改键,因此 std::hash 的规范看起来比 std::hash 更合适。你不同意吗?
    猜你喜欢
    • 1970-01-01
    • 2013-04-09
    • 2017-11-10
    • 1970-01-01
    • 2015-07-05
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 2012-09-08
    相关资源
    最近更新 更多