如何使用const键复制unordered_map?

问题描述 投票:6回答:1

简单代码:

#include <unordered_map>

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

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

错误C2280'std :: hash <_Kty> :: hash(void)':尝试引用已删除的函数

这基本上说unordered_map在其内部并不期望关键是不变的

PS:我已经读过类似问题的answer

关联容器只将(key,value)对公开为std :: pair,因此key类型的附加const是多余的。

但它并不能解释为什么带有const键的hashmap实际上无法使用以及如何规避问题

c++ stl
1个回答
8
投票

类型

std::unordered_map<const int, int> 

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

复制unordered_set时需要工作哈希。要制作工作哈希:

  1. 您可以自己专门化std::hash<const int>,以便不再删除它: namespace std { // fixes it but is a bad idea - could break in future revisions of the standard template<> struct hash<const int> : hash<int>{}; }
  2. 或者您可以显式声明您的哈希: std::unordered_map<const int, int, std::hash<int>>
  3. 或者你可以摆脱键中的const(因为它没有效果): std::unordered_map<int, int>

附录:

删除意味着删除非专业化std::hash的构造函数:

template <typename T>
struct hash
{
   hash() = delete;
   hash(const hash) = delete;
   // more deleted methods
};

通过“删除”,意味着它不存在(既不是用户提供也不是默认)。

你可以在cppreference看到这个,他们使用启用/禁用的术语:

对于每个类型的密钥,库和用户都没有提供启用的特化std :: hash,该特化存在并被禁用。

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

禁用的特化不满足Hash,[...] std :: is_default_constructible_v,std :: is_copy_constructible_v [...]都是假的。换句话说,它们存在,但不能使用。

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

© www.soinside.com 2019 - 2024. All rights reserved.