Ответ
Требования зависят от типа контейнера:
1. Для упорядоченных контейнеров (std::map, std::set, std::multimap, std::multiset):
Ключ должен поддерживать строгое слабое упорядочение. На практике это означает, что для типа ключа должен быть определен оператор сравнения operator< или предоставлен пользовательский функтор-компаратор.
// Пример ключа для std::set или std::map
struct Point {
int x, y;
// Определяем оператор < для строгого слабого упорядочения
bool operator<(const Point& other) const {
// Используем std::tie для лексикографического сравнения
return std::tie(x, y) < std::tie(other.x, other.y);
}
};
// Использование
std::set<Point> pointSet;
std::map<Point, std::string> pointMap;
2. Для неупорядоченных контейнеров (std::unordered_map, std::unordered_set):
Ключ должен быть хешируемым и сравнимым на равенство.
- Для типа должен быть специализирован
std::hash. - Должен быть определен оператор
operator==или предоставлен предикат равенства.
// Пример ключа для std::unordered_set или std::unordered_map
struct Point {
int x, y;
// Определяем оператор ==
bool operator==(const Point& other) const {
return x == other.x && y == other.y;
}
};
// Специализируем std::hash для Point
namespace std {
template<> struct hash<Point> {
size_t operator()(const Point& p) const noexcept {
// Комбинируем хэши полей. Используем XOR и сдвиг для лучшего распределения.
return hash<int>()(p.x) ^ (hash<int>()(p.y) << 1);
}
};
}
// Использование
std::unordered_set<Point> pointUSet;
std::unordered_map<Point, int> pointUMap;
Важно: Для пользовательских типов в качестве ключа в std::unordered_* контейнерах часто также требуется определить operator== в том же пространстве имен, что и сам тип (или в std), чтобы ADL мог его найти.