Как правильно перегрузить оператор <в структуре, чтобы разрешить использование в наборе в C ++ - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь создать набор структур в C ++, действие, требующее перегрузки оператора «<». </p>

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

То, что я пробовал, работает:

#include <iostream>
#include <set>

struct Coordinate {
    int x, y;
};

bool operator<(const Coordinate& l, const Coordinate& r) {
    return l.x * l.y < r.x * r.y;
}

int main() {
    std::set<Coordinate> mySet;
    mySet.insert(Coordinate{ 5,5 });
}

Я хотел бы сделать что-то вроде этого:

#include <iostream>
#include <set>

struct Coordinate {
    int x, y;

    bool operator<(const Coordinate& other) {
        return this->x * this->y < other.x * other.y;
    }
};

int main() {
    std::set<Coordinate> mySet;
    mySet.insert(Coordinate{ 5,5 });
}

Однако последний не компилируется.

сообщение об ошибке:

1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\xstddef(127,1): error C2678: binary '<': no operator found which takes a left-hand operand of type 'const _Ty' (or there is no acceptable conversion)
1>        with
1>        [
1>            _Ty=Coordinate
1>        ]
1>C:\CppWorkspace\Dungeons of Doom\Dungeons of Doom\src\TestMain.cpp(7,7): message : could be 'bool Coordinate::operator <(const Coordinate &)'
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\xstddef(127,1): message : while trying to match the argument list '(const _Ty, const _Ty)'
1>        with
1>        [
1>            _Ty=Coordinate
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\xstddef(126): message : while compiling class template member function 'bool std::less<Coordinate>::operator ()(const _Ty &,const _Ty &) const'
1>        with
1>        [
1>            _Ty=Coordinate
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\xutility(1469): message : see reference to function template instantiation 'bool std::less<Coordinate>::operator ()(const _Ty &,const _Ty &) const' being compiled
1>        with
1>        [
1>            _Ty=Coordinate
1>        ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\xmemory(1318): message : see reference to class template instantiation 'std::less<Coordinate>' being compiled
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\xmemory(1318): message : see reference to variable template 'const bool is_empty_v<std::less<Coordinate> >' being compiled
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.25.28508\include\set(54): message : see reference to class template instantiation 'std::_Tree<std::_Tset_traits<_Kty,_Pr,_Alloc,false>>' being compiled
1>        with
1>        [
1>            _Kty=Coordinate,
1>            _Pr=std::less<Coordinate>,
1>            _Alloc=std::allocator<Coordinate>
1>        ]
1>C:\CppWorkspace\Dungeons of Doom\Dungeons of Doom\src\TestMain.cpp(17): message : see reference to class template instantiation 'std::set<Coordinate,std::less<Coordinate>,std::allocator<Coordinate>>' being compiled

Я новичок в C ++, и мне было интересно, есть ли способ сделать что-то подобное.

Ответы [ 3 ]

0 голосов
/ 31 марта 2020

Лучше, чтобы операторы сравнения были дружественными функциями.

#include <iostream>
#include <set>

struct Coordinate {
    int x, y;

    friend bool operator<(const Coordinate& lhs, const Coordinate& rhs) {
        return lhs.x * lhs.y < rhs.x * rhs.y;
    }
};

int main() {
    std::set<Coordinate> mySet;
    mySet.insert(Coordinate{ 5,5 });
}
0 голосов
/ 31 марта 2020

operator< должно быть const, но большая проблема заключается в том, что оператор не выполняет строгое слабое упорядочение , упомянутое в названном требовании Сравнить .

Рассмотрим этот код:

#include <iostream>
#include <set>

struct Coordinate {
    int x, y;
    Coordinate(int X, int Y) : x(X), y(Y) {}

    bool operator<(const Coordinate& other) const {
        return this->x * this->y < other.x * other.y;
    }
};

int main() {
    std::set<Coordinate> mySet;
    mySet.emplace(1, 5);
    mySet.emplace(5, 1);
    std::cout << mySet.size() << '\n';
}

Это выдаст 1, так как второй Coordinate будет считаться равным первому при использовании этого operator<.

Правильная версия может выглядеть следующим образом:

    bool operator<(const Coordinate& other) const {
        return x==other.x ? y < other.y : x < other.x;
    }

Или лучше использовать std::tie из <tuple>, что значительно упрощает это:

    bool operator<(const Coordinate& other) const {
        return std::tie(x, y) < std::tie(other.x, other.y);
    }
0 голосов
/ 31 марта 2020

Вы смотрели на ошибку компиляции?

Как говорится, метод должен быть постоянным

bool operator<(const Coordinate& other)  const {   // const the < operator
        return this->x * this->y < other.x * other.y;
    }
...