简单代码:
#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实际上无法使用以及如何规避问题
类型
std::unordered_map<const int, int>
使用默认的第三个参数std::hash<const int>
。与std::hash<int>
不同,这种散列类型不是标准库专用的,deleted
也是如此(如错误消息所示)。
复制unordered_set时需要工作哈希。要制作工作哈希:
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>{};
}
std::unordered_map<const int, int, std::hash<int>>
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 [...]都是假的。换句话说,它们存在,但不能使用。
因此,这些构造函数必须不可用(删除它们是最好的方法)。