Middle
What properties should an object have to be used as a key in associative containers?
sobes.tech AI
Answer from AI
In the standard C++ library, to use a type as a key in std::map or std::unordered_map, it must possess the following properties:
For std::map (based on a red-black tree):
- Comparability: The type must support a weak strict ordering, usually implemented by the
<operator. This<operator must be:- Irreflexive:
x < xis always false. - Transitive: If
f(x, y)andf(y, z)are true, thenf(x, z)is also true (wherefis the relation, e.g.,<). - Asymmetric: If
x < yis true, theny < xis false. - Alternatively, a comparator (e.g., a lambda function or functor class) can be provided when creating the container.
- Irreflexive:
For std::unordered_map (based on a hash table):
- Hashability: There must be a hash function defined for the type, which computes a
std::size_tvalue based on an object of that type. This is usually implemented by:- Specializing the
std::hashtemplate class for the type. - Using built-in hash functions for primitive types and pointers.
- For user-defined types, it is often necessary to explicitly define a specialization of
std::hashor provide a hash functor when creating the container.
- Specializing the
- Equality comparability: The type must support equality comparison, usually implemented by the
==operator. This operator must be:- Reflexive:
x == xis always true. - Symmetric: If
x == yis true, theny == xis also true. - Transitive: If
x == yandy == zare true, thenx == zis also true. - Alternatively, a comparison function for equality (e.g., a lambda or functor) can be provided when creating the container.
- Reflexive:
Example specialization of std::hash:
#include <functional> // For std::hash
struct Point {
int x, y;
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
// Specialization of std::hash for Point to make it hashable
namespace std {
template <>
struct hash<Point> {
size_t operator()(const Point& p) const {
// Simple combined hash function
return hash<int>()(p.x) ^ (hash<int>()(p.y) << 1);
}
};
}
Example comparator for std::map:
#include <map>
struct Point {
int x, y;
};
struct PointCompare {
bool operator()(const Point& a, const Point& b) const {
if (a.x != b.x) {
return a.x < b.x;
}
return a.y < b.y;
}
};
// Creating a map with a custom comparator
// std::map<Point, int, PointCompare> my_map;