I'm trying to create an std::unordered_map that takes a std::pair as key, and returns a size_t as value. The tricky part for me is that I want custom hash function for my map to disregard the order of the members of the key std::pair. I.e:
std::pair<int,int> p1 = std::make_pair<3,4>;
std::pair<int,int> p2 = std::make_pair<4,3>;
std::unordered_map<std::pair<int,int>, int> m;
m[p1] = 3;
// m[p2] should now also return 3!
This is not a clear cut MWE but it's a cut out of what I'm trying to do in my program:
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
#include <memory>
#include <unordered_map>
#include <functional>
class Point
{
public:
static size_t id_counter;
size_t id;
Point()=default;
~Point()=default;
bool operator==(const Point& rhs)
{
return id == rhs.id;
}
friend std::ostream& operator<<(std::ostream& os, Point& P);
};
size_t Point::id_counter = 0;
class Hasch_point_pair
{
public:
size_t operator()(const std::pair<Point*, Point*>* p) const
{
// XOR hash. We don't care about collision we're FREAKS
auto h1 = std::hash<size_t>()(p->first->id);
auto h2 = std::hash<size_t>()(p->second->id);
return h1^h2;
}
};
int main(int argc, char const *argv[])
{
auto p1 = std::make_unique<Point>();
auto p2 = std::make_unique<Point>();
auto p3 = std::make_unique<Point>();
auto p4 = std::make_unique<Point>();
std::unordered_map<std::pair<Point*, Point*>*, size_t*, Hasch_point_pair> m;
auto p = std::make_unique<std::pair<Point*, Point*>>(p1.get(),p2.get());
auto p_hmm = std::make_unique<std::pair<Point*, Point*>>(p2.get(),p1.get());
size_t value = 3;
m[p.get()] = &value;
std::cout << "m[p] = " << m.at(p.get()) << std::endl;
std::cout << "m[p_hmm] = " << m.at(p_hmm.get()) << std::endl;
}
One thought I had was to compare the id's of each Point and always use the Point with the largest id member variable as the first hash, but I haven't gotten it to work. Does it make sense?
class Hasch_point_pair
{
public:
size_t operator()(const std::pair<Point*, Point*>* p) const
{
if (p->first->id > p->second->id)
{
auto h1 = std::hash<size_t>()(p->first->id);
auto h2 = std::hash<size_t>()(p->second->id);
return h1^h2;
}
else
{
// Note switched order of hash1 and hash2!
auto h2 = std::hash<size_t>()(p->first->id);
auto h1 = std::hash<size_t>()(p->second->id);
return h1^h2;
}
}
};