如何使用const键复制unordered_map?

Ale*_*nov 6 c++ stl

简单的代码:

#include <unordered_map>

int main()
{
  std::unordered_map<const int, int> m;
  std::unordered_map<const int, int> m1 = m;
}
Run Code Online (Sandbox Code Playgroud)

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

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

基本上unordered_map在内部表示不希望密钥保持不变

PS:我已经阅读了类似问题的答案

关联容器仅将(key,value)对公开为std :: pair,因此键类型上的其他const是多余的。

但这并没有解释为什么带有const键的哈希图实际上是不可用的,以及如何规避此问题

Mic*_*ler 8

类型

std::unordered_map<const int, int> 
Run Code Online (Sandbox Code Playgroud)

使用默认的第三个参数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>{};
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者,您可以明确声明您的哈希值:

    std::unordered_map<const int, int, std::hash<int>> 
    
    Run Code Online (Sandbox Code Playgroud)
  3. 或者,您可以删除键中的const(因为它无效):

    std::unordered_map<int, int> 
    
    Run Code Online (Sandbox Code Playgroud)

附录

Deleted表示将非专业化的构造函数std::hash删除:

template <typename T>
struct hash
{
   hash() = delete;
   hash(const hash) = delete;
   // more deleted methods
};
Run Code Online (Sandbox Code Playgroud)

“删除”表示它不存在(既不是用户提供的也不是默认值)。

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

对于库和用户均未为其提供启用的专业化std :: hash的每个类型Key,该专业化存在且被禁用。

由于std::hash<const int>不是库提供的,除非用户提供,否则它将被禁用。接下来,文本说明什么是禁用

禁用的专业不能满足哈希,[...] std :: is_default_constructible_v,std :: is_copy_constructible_v [...]全部为假。换句话说,它们存在,但不能使用。

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