Множество Объектов и перегрузка оператора "<"

Рейтинг: 0Ответов: 1Опубликовано: 30.03.2023

Имеется вот такой код:

#include <iostream>
#include <set>

using namespace std;

using ulli = unsigned long long;
using lli = long long;
using lld = long double;
using usi = unsigned short;

class Atom
{
    friend bool operator <(const Atom& thisis, const Atom& other);
private:
    lld x, y, z;
public:

Atom(lld x, lld y, lld z)
{
    this->x = x;
    this->y = y;
    this->z = z;
}

void Print()
{
    cout << this->x << " " << this->y << " " << this->z << endl;
}
}

bool operator <(const Atom& thisis, const Atom& other)
{
    return sqrt(thisis.x * thisis.x + thisis.y * thisis.y + thisis.z * thisis.z) < sqrt(other.x * other.x + other.y * other.y + other.z * other.z);
}

int main()
{
    set <Atom> st
    {
        Atom(2.813, 2.813, 2.8135),
            Atom(0, 0, 0),
            Atom(2.813, 0, 0),
            Atom(0, 2.813, 0),
            Atom(2.813, 2.813, 0),
            Atom(0, 0, 2.813),
            Atom(2.813, 0, 2.813),
            Atom(0, 2.813, 2.813),
            Atom(1.4065, 1.4065, 1.4065)
    };
    for (auto elem : st) elem.Print();
    return 0;
}

В итоге выводиться всего 5 элементов множества, хотя загружается 9. Насколько я понял, ошибка происходит на этапе распределения в set элементов при помощи перегруженного оператора, а значит я как-то неправильного его перегрузил, но что не так понять не могу. Изначально сделал перегрузку в самом классе, но вылазила ошибка, что как бы set не видит этой перегрузки. Скажите как сделать это правильнее. Я новичок, так что не бейте.

Ответы

▲ 2Принят

Допустим, a = Atom(2.813, 0, 0) и b = Atom(0, 2.813, 0).

У вас a < b == false и b < a == false, поэтому set считает a и b одинаковыми, и отказывается вставлять b, если a уже присутствует.

Правильно - использовать лексикографическое сравнение. Например так:

if (a.x < b.x) return true;
if (a.x > b.x) return false;
if (a.y < b.y) return true;
if (a.y > b.y) return false;
if (a.z < b.z) return true;
if (a.z > b.z) return false;
return false;

Или, в С++20 делают так:

friend auto operator<=>(const Atom &, const Atom &) = default;

Это автоматически генерирует правильные ==, !=, <, <=, >, >=.


Изначально сделал перегрузку в самом классе, но вылазила ошибка, что как бы set не видит этой перегрузки.

Должно работать и так и так. Если интересно - покажите ошибку.


Еще, если бы вы вдруг хотели оставить текущее поведение, стоило бы убрать sqrt(...), который все равно не влияет на ответ.