Why can't I compile an unordered_map with a pair as key?
You need to provide a suitable hash function for your key type. A simple example:
#include <unordered_map>
#include <functional>
#include <string>
#include <utility>
// Only for pairs of std::hash-able types for simplicity.
// You can of course template this struct to allow other hash functions
struct pair_hash {
template <class T1, class T2>
std::size_t operator () (const std::pair<T1,T2> &p) const {
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
// Mainly for demonstration purposes, i.e. works but is overly simple
// In the real world, use sth. like boost.hash_combine
return h1 ^ h2;
}
};
using Vote = std::pair<std::string, std::string>;
using Unordered_map = std::unordered_map<Vote, int, pair_hash>;
int main() {
Unordered_map um;
}
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 for std::pair
, as well as std::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.
Why does std::map accept a std::pair as key, but std::unordered_map does not?
std::map
doesn't hash anything. It uses std::less
as its default comparator. It will work for any type that supports operator<
.
std::unordered_map
sorts its elements using a hash provided by std::hash
.
It so happens that std::pair
provides operator<
, but doesn't have a specialization for std::hash
.
pair<int,int> pair as key of unordered_map issue
This happens because there is no specialization for std::tr1::hash<Key>
with Key = std::pair<int, int>
.
You must to specialize std::tr1::hash<Key>
with Key = std::pair<int, int>
before declaring tr1::unordered_map<Pair,bool> h;
.
This happens because std
don't know how to hash a pair<int, int>
.
Following there is a example of how to specialize std::tr1::hash<>
template <>
struct std::tr1::hash<std::pair<int, int> > {
public:
size_t operator()(std::pair<int, int> x) const throw() {
size_t h = SOMETHING;//something with x
return h;
}
};
Why can't I use pair as key of unordered_set / unordered_map?
The unordered_*
containers need a hash function. By default, they use std::hash
but there is no specialization of std::hash
for std::pair<T1,T2>
provided in the standard library. On the other hand, the ordered containers rely on std::less
(by default) and std::pair
does have operator<
provided. That's why it just works.
In order to have an unordered container with a pair
, you will have to provide a hash functor yourself. For example:
struct SimpleHash {
size_t operator()(const std::pair<int, int>& p) const {
return p.first ^ p.second;
}
};
std::unordered_set<std::pair<int, int>, SimpleHash> S;
S.insert(std::make_pair(0, 1));
Creating unordered map in C++ for counting the pairs
You can't just use unordered_map
with a pair
because there is no default hash implemented.
You can however use map
which should work fine for your purpose because pair
does implement <
.
See Why can't I compile an unordered_map with a pair as key? when you really want unordered_map
.
You can construct pair
with curly braces like this
umap[{arr[i-1], arr[i]}]++;
I think from C++11 onward, but it might be C++14 or even C++17
Why is this unordered_map not finding existing keys? (C++14)
Pointers are not the objects they point to.
You are using pointers as keys. The objects equal operator will be ignored.
Related Topics
Using Opencv and Svm With Images
Purpose of Returning by Const Value
How to Get Memory Usage At Runtime Using C++
_File_, _Line_, and _Function_ Usage in C++
Lock-Free Progress Guarantees in a Circular Buffer Queue
How to Initialize Base Class Member Variables in Derived Class Constructor
Why Would the Behavior of Std::Memcpy Be Undefined For Objects That Are Not Triviallycopyable
Is There a Replacement For Unistd.H For Windows (Visual C)
Getting Std :: Ifstream to Handle Lf, Cr, and Crlf
How to Call a Base Class'S Virtual Function If I'M Overriding It
How to Loop Through a C++ Map of Maps
Differences Between Unique_Ptr and Shared_Ptr
Pre-2016 Valgrind: Memory Still Reachable With Trivial Program Using ≪Iostream≫