关于c ++:如何使用const键复制unordered_map?

How to copy unordered_map with a const key?

简单代码:

1
2
3
4
5
6
7
#include <unordered_map>

int main()
{
  std::unordered_map<const int, int> m;
  std::unordered_map<const int, int> m1 = m;
}

生成复杂的编译错误消息:

Error C2280 'std::hash<_Kty>::hash(void)': attempting to reference a
deleted function

基本上说,unordered_map在其内部并不期望密钥是恒定的。

PS:我读过类似问题的答案:

The associative containers only expose the (key,value) pair as
std::pair, so the additional const on the
key type is superfluous.

但这并不能解释为什么带有const键的hashmap实际上不可用,以及如何绕过这个问题。


类型

1
std::unordered_map<const int, int>

使用默认的第三个参数std::hash。与std::hash不同,这种散列类型不是由标准库专门化的,deleted也是如此(正如错误消息所说)。

复制无序的存储集时需要工作哈希。要创建有效哈希,请执行以下操作:

  • 您可以自己专门化std::hash,这样它就不再被删除:

    1
    2
    3
    4
    5
    6
    namespace std
    {
      // fixes it but is a bad idea - could break in future revisions of the standard
      template<>
      struct hash<const int> : hash<int>{};
    }
  • 或者您可以显式地声明散列:

    1
    std::unordered_map<const int, int, std::hash<int>>
  • 或者您可以去掉密钥中的const(因为它没有效果):

    1
    std::unordered_map<int, int>
  • 附录:

    删除是指删除非专用std::hash的构造函数:

    1
    2
    3
    4
    5
    6
    7
    template <typename T>
    struct hash
    {
       hash() = delete;
       hash(const hash) = delete;
       // more deleted methods
    };

    "删除"表示它不存在(既不提供用户也不默认)。

    您可以在cppreference中看到这一点,它们使用启用/禁用的术语:

    For every type Key for which neither the library nor the user provides an enabled specialization std::hash, that specialization exists and is disabled.

    由于std::hash不是由库提供的,因此除非由用户提供,否则它将被禁用。接下来,文本解释什么是禁用:

    Disabled specializations do not satisfy Hash, [...] std::is_default_constructible_v, std::is_copy_constructible_v [...] are all false. In other words, they exist, but cannot be used.

    因此,这些构造函数必须是不可用的(删除它们是最好的方法)。