std :: set уже содержит член, хотя он отличается - PullRequest
3 голосов
/ 05 августа 2020

Я написал следующий простой код:

std::set<Edge> edges;
Edge edge1("a","b");
Edge edge2("a","c");
edges.insert(edge1);
if (edges.find(edge2) != edges.end()) //edge2 already exists
    std::cout << "OH NO!";

В котором есть ошибка с тех пор, как ОН НЕТ! печатается, хотя edge1 и edge2 отличаются друг от друга.

Вот как я реализовал operator == и operator < для Edge:

bool operator==(const Edge &e1, const Edge &e2) {
    return (e1.source == e2.source) && (e1.destination == e2.destination);
}

bool operator<(const Edge &e1, const Edge &e2) {
    return e1.source < e2.source;
}

What вызывает эту ошибку?

1 Ответ

6 голосов
/ 05 августа 2020

Согласно вашему operator<, Edge("a","b") и Edge("a","c") равны. Вам нужно указать компьютеру, как вы хотите отсортировать элементы, если первый элемент такой же. Самый простой способ - провести лексикографическую сортировку. std::tie отлично подходит для этого.

Для этого вам понадобится #include <tuple>.

bool operator<(const Edge &e1, const Edge &e2) {
    return std::tie(e1.source, e1.destination) < std::tie(e2.source, e2.destination);
}

Изменить: нет, не определяйте другие операторы с точки зрения operator< если достаточно просто

Или сделайте. Тебе решать. Я не уверен, какой стиль предпочитаю.

bool operator==(const Edge &e1, const Edge &e2) {
    return e1.source == e2.source && e1.destination == e2.destination;
}

отлично читается и поддерживается. Может быть, если бы было сложнее, я бы определил это в терминах operator<.

Старое предложение:

Также рекомендуется определять все остальные функции сравнения в терминах operator<:

bool operator==(const Edge &e1, const Edge &e2) {
    return !(e1 < e2) && !(e2 < e1);
}

Не обязательно наиболее эффективно (в зависимости от вашего компилятора), но если вам абсолютно не нужно, чтобы он работал как можно быстрее, это делает ваш код супер-обслуживаемым.

...