为什么我可以用一对键编译unordered_map?
我正在尝试创建一个unordered_map
与整数映射:
#include <unordered_map>
using namespace std;
using Vote = pair<string, string>;
using Unordered_map = unordered_map<Vote, int>;
我有一个类,其中我将unordered_map
为私人成员。
但是,当我尝试编译时,我会遇到以下错误:
/applications/xcode.app/contents/developer/toolchains/xcodedefault.xctoolchain/usr/include/c ++/c ++/v1/type_traits:948:38:38:demit Intantiatiation' :__ 1 :: basic_string&gt; &gt;'
如果我使用常规地图,例如map&lt; pair&lt; string,string&gt; gt;
而不是unordered_map
。
是否不可能将Pair
用作无序地图中的键?
I am trying to create an unordered_map
to map pairs with integers:
#include <unordered_map>
using namespace std;
using Vote = pair<string, string>;
using Unordered_map = unordered_map<Vote, int>;
I have a class where I have declared an Unordered_map
as a private member.
However, I am getting the following error when I try to compile it:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/type_traits:948:38: Implicit instantiation of undefined template 'std::__1::hash, std::__1::basic_string > >'
I am not getting this error if I use a regular map like map<pair<string, string>, int>
instead of an unordered_map
.
Is it not possible to use pair
as key in unordered maps?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您需要为密钥类型提供合适的哈希功能。一个简单的例子:
这将起作用,但没有最好的Hash-Properties †。您可能想看一下
BOOST.HASH_COMBINE
在结合哈希时为更高质量的结果。还可以更详细地讨论这一点 - 包括BOOST的上述解决方案 - 在此答案。
对于现实世界的使用:boost还提供功能集 <代码> hash_value 已经为
std ::配对
以及std :: Tuple
和大多数标准容器提供了哈希功能。†更确切地说,它会产生太多的碰撞。例如,每个对称对将哈希至0,而仅因排列而不同的对将具有相同的哈希。这对于您的编程练习可能很好,但可能会严重损害现实世界法规的性能。
You need to provide a suitable hash function for your key type. A simple example:
This will work, but not have the best hash-properties†. You might want to have a look at something like
boost.hash_combine
for higher quality results when combining the hashes. This is also discussed in greater detail – including the aforementioned solution from boost – in this answer.For real world use: Boost also provides the function set
hash_value
which already provides a hash function forstd::pair
, as well asstd::tuple
and most standard containers.†More precisely, it will produce too many collisions. E.g., every symmetric pair will hash to 0 and pairs that differ only by permutation will have the same hash. This is probably fine for your programming exercise, but might seriously hurt performance of real world code.
解决此问题的我首选的方法是定义
键
函数,该功能将您的配对转换为唯一的整数(或任何可用的数据类型)。该密钥不是哈希键。这是一对数据的唯一ID,然后将通过unordered_map
最佳地哈希。例如,您想定义类型的unordered_map
,并且要使用
map [make_pair(i,j)] = value
或map.find( make_pair(i,j))
在地图上操作。然后,您必须告诉系统如何放置一对整数make_pair(i,j)
。取而代之的是,我们可以定义然后将映射的类型更改为
我们现在可以使用
map [key(i,j)] = value
或map.find(key(i,(i,) j))
要在地图上操作。现在,每个make_pair
现在都变为呼叫inline键
函数。此方法可以确保将密钥最佳地放置,因为现在哈希零件是由系统完成的,它将始终选择内部哈希表尺寸以确保每个存储桶的可能性同样可能。但是,您必须使自己100%确定
键
是每对唯一的,即,没有两个不同的对可以具有相同的键,否则可能会有很难找到的错误。My preferred way of solving this problem is to define a
key
function that transforms your pair into a unique integer (or any hashable data type). This key is not the hash key. It is the unique ID of the pair of data that will then be optimally hashed by theunordered_map
. For example, you wanted to define anunordered_map
of the typeAnd you want to use
Map[make_pair(i,j)]=value
orMap.find(make_pair(i,j))
to operate on the map. Then you'll have to tell the system how to hash a pair of integersmake_pair(i,j)
. Instead of that, we can defineand then change the type of the map to
We can now use
Map[key(i,j)]=value
orMap.find(key(i,j))
to operate on the map. Everymake_pair
now becomes calling the inlinekey
function.This method guarantees that the key will be optimally hashed, because now the hashing part is done by the system, which will always choose the internal hash table size to be prime to make sure every bucket is equally likely. But you have to make yourself 100% sure that the
key
is unique for every pair, i.e., no two distinct pairs can have the same key, or there can be very difficult bugs to find.如果使用
Pair
不是严格的要求,则只需两次使用地图即可。If using
pair
is not a strict requirement, you can simply use map twice.对于配对键,我们可以使用Boost Pair Hash函数:
同样,我们可以将Boost Hash用于向量,
For pair key, we can use boost pair hash function:
Similarly we can use boost hash for vectors,
参考: c ++标准库:教程和参考,第二版第7.9.2章:创建和控制无序的容器,
我在Google中找到的所有解决方案
XOR
XOR 生成对,这完全不好。请参阅 why-is-is-xor-the-default-to-to -combine-hashes 。但是,这本书为我们提供了最佳的解决方案,使用
hash_combine
,它取自boost
。当我在在线法官中对其进行测试时,该解决方案要比XOR好得多( noreflow noreferrer“> atcoder )。我将代码作为模板组织为以下模板。您可以尽可能复制和粘贴它。更改它以适合任何自定义结构/类是很方便的。更新:添加元组的哈希模板。
Reference: C++ Standard Library: A tutorial and reference, Second version Chapter 7.9.2: Creating and Controlling unordered Container
All solutions I found in Google use
XOR
to generate hashcode ofpair
, which is totally bad. see why-is-xor-the-default-way-to-combine-hashes. However, the book has given us the best solution, usinghash_combine
, which is taken fromBoost
. The solution is much better than XOR when I tested it in Online Judge(Atcoder). I organized the code as a template as follow. You can copy and paste it as much as you can. And it is convenient to change it to fit any custom struct/class.Update: add hash template for tuple.
正如您的汇编错误所示,在您的std nesspace中没有有效的
std :: std :: hash&lt; std :: pair&lt; std :: string,std :: string&gt;&gt;
。根据我的编译器的说法:
您可以为
std :: Hash&lt; pote&gt;
提供自己的专业化,如下:As your compilation error indicates, there is no valid instantiation of
std::hash<std::pair<std::string, std::string>>
in your std namespace.According to my compiler:
You can provide your own specialization for
std::hash<Vote>
as follows:我已经简化了 @youngforest的答案仅与OP所要求的配对一起工作(= =不使用任意长度) 。我还将样板代码最小化:
它使用与Boost库中相同的逻辑(比XOR版本更好)。
I've simplified @YoungForest's answer to only work with pairs (= not with arbitrary length tuples) as was requested by the OP. I've also minimized the boilerplate code:
It uses the same logic as in the boost library (that is better than the xor version).
在 要求使用一个示例 lambda表达式而不是定义哈希功能。我同意 MIT Augen ,这可能会损害可读性,尤其是如果您想实现更普遍的解决方案。因此,我想通过专注于
std :: pair&lt; std :: String,std :: String&gt;
的特定解决方案来简短示例。该示例还使用a 手工制作std :: Hash&lt; std :: String&gt;
函数调用的组合:In the comments on the answer by Baum mit Augen, the user Joe Black asked for an example on using a lambda expressions instead of defining a hash function. I agree with the opinion of Baum mit Augen, that this might harm readability, especially if you want to implement a more universal solution. Therefore, I'd like to keep my example short by focusing on a specific solution for
std::pair<std::string, std::string>
, as presented by the OP. The example also uses a handcrafted combination ofstd::hash<std::string>
function calls:Code on Ideone
此类问题有一个 hack
使用
std:unordered_map
string> string
查看以下示例 -
我需要哈希矩形
甚至有效,即使您需要创建十进制或双重键的哈希:)
There is a hack to such problems
Use a
std:unordered_map
ofstring
Look at the following example-
I am required to hash the endpoint(corner) of a rectangle
Such hack even works if you are required to create a hash of decimal or double as a key :)