As here there is no total order relationship between Object
s, one possibility is to use unorded_map
instead of map
.
Therefore the object
class needs at least an overloaded ==
operator and a custom hash function:
#include <unordered_map>
#include <iostream>
class Object
{
public:
int x, y;
Object(int x, int y) : x(x), y(y) {};
bool operator==(const Object& o) const
{
std::cout << "equal hashes, using == operator on (" << x << "," << y << ")\n";
auto isequal = x == o.x && y == o.y;
std::cout << "objects are " << (isequal ? "" : "not ") << "equal\n";
return isequal;
};
friend std::ostream& operator<<(std::ostream& os, const Object& o);
};
std::ostream& operator<<(std::ostream& os, const Object & o)
{
os << "(" << o.x << "," << o.y << ")";
return os;
}
struct ObjectHash {
size_t operator()(const Object& o) const
{
std::cout << "hashing (" << o.x << "," << o.y << ")\n";;
return o.x + o.y; // purposly bad hash function, so we get collisions
// (o.x * 127) ^ o.y would be better, still not ideal
}
};
int main()
{
Object o1(1, 2);
Object o2(3, 4); // different from o1, o3 and o4
Object o3(1, 2); // equal to o1
Object o4(2, 1); // different from o1, o2 and o3 but same hash as o1
std::unordered_map<Object, int, ObjectHash> objmap;
std::cout << "Inserting " << o1 << "\n"; objmap.insert(std::make_pair(o1, 11));
std::cout << "Inserting " << o2 << "\n"; objmap.insert(std::make_pair(o2, 22));
std::cout << "Inserting " << o3 << "\n"; objmap.insert(std::make_pair(o3, 33));
std::cout << "Inserting " << o4 << "\n"; objmap.insert(std::make_pair(o4, 33));
}
The std::cout
s are there for illustration purposes.
Output:
Inserting (1,2)
hashing (1,2)
Inserting (3,4)
hashing (3,4)
Inserting (1,2)
hashing (1,2)
equal hashes, using == operator on (1,2)
objects are equal
Inserting (2,1)
hashing (2,1)
equal hashes, using == operator on (2,1)
objects are not equal