map
stores its elements ordered by key; so you need to define that ordering.
If the key is a class type, you can either overload operator<
so that the default ordering of std::less
works:
bool operator<(my_thing const & a, my_thing const & b) {
// return true if "a" is ordered before "b"
}
std::map<my_thing, something_else> my_map;
or you can provide your own comparison functor
struct compare_my_thing {
bool operator()(my_thing const & a, my_thing const & b) {
// return true if 'a' is ordered before 'b'
}
};
std::map<my_thing, something_else, compare_my_thing> my_map;
unordered_map
is a hash table; so you need to define both a hash function and a means to compare for equality (since hashes are generally not unique). Again, you can either provide overloads so that the defaults (std::hash
and std::equal_to
) work:
namespace std {
template <>
struct hash<my_thing> {
std::size_t operator()(my_thing const & t) const {
// return hash of 't'
}
};
}
bool operator==(my_thing const & a, my_thing const & b) {
// return true if 'a' and 'b' are equal
}
std::unordered_map<my_thing, something_else> my_map;
or you can provide your own functors
struct hash_my_thing {
std::size_t operator()(my_thing const & t) const {
// return hash of 't'
}
};
struct compare_my_thing {
bool operator()(my_thing const & a, my_thing const & b) {
// return true if 'a' and 'b' are equal
}
};
std::unordered_map<my_thing, something_else, hash_my_thing, compare_my_thing> my_map;
so why is the template so intrusive? i mean it should act as a container, not minding what is the object about nor what is inside of it
Different containers have different requirements from their contained types. For example, yhey all require them to be destructible, since containers are responsible for managing their lifetime. Some require them to be movable; for example, vector
needs to move elements when allocating a larger array to keep them in. Associative containers have extra requirements on their key types, to allow them to be used as keys.