Почему const необходим для "operator>", но не для "operator <"?
Рассмотрим этот фрагмент кода:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator < (const MyStruct& other) {
return (key < other.key);
}
};
int main() {
std::vector < MyStruct > vec;
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));
vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
std::sort(vec.begin(), vec.end());
for (const MyStruct& a : vec) {
cout << a.key << ": " << a.stringValue << endl;
}
}
Он компилируется отлично и дает результат, которого можно было бы ожидать. Но если я попытаюсь отсортировать структуры в порядке убывания:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator > (const MyStruct& other) {
return (key > other.key);
}
};
int main() {
std::vector < MyStruct > vec;
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));
vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
std::sort(vec.begin(), vec.end(), greater<MyStruct>());
for (const MyStruct& a : vec) {
cout << a.key << ": " << a.stringValue << endl;
}
}
Это дает мне ошибку. Вот полное сообщение:
/usr/include/c++/7.2.0/bits/stl_function.h: В экземпляре 'constexpr bool std :: больше <_Tp> :: operator() (const _Tp &, const _Tp &) const [с _Tp = MyStruct ]:
/usr/include/c++/7.2.0/bits/stl_function.h:376:20: ошибка: нет соответствия для 'operator>' (типы операндов: 'const MyStruct' и 'const MyStruct')
{return __x> __y; } }
Похоже, что эта функция прямо здесь не имеет определителя const
:
bool operator > (const MyStruct& other) {
return (key > other.key);
}
Если я добавлю его,
bool operator > (const MyStruct& other) const {
return (key > other.key);
}
Тогда все хорошо. Почему это так? Я не слишком хорошо знаком с перегрузкой оператора, поэтому я просто поместил его в память, что нам нужно добавить const
но все же странно, почему она работает для operator<
без const
.
Ответы
Ответ 1
Вы получаете разные формы поведения, потому что на самом деле вы вызываете две разные (перегруженные) функции сортировки.
В первом случае вы вызываете два параметра std::sort
, которые используют operator<
непосредственно. Поскольку итераторы к вашим векторным элементам создают неконстантные ссылки, он может применять operator<
just fine.
Во втором случае вы используете трехпараметрическую версию std::sort
. Тот, который принимает функтор. Вы проходите std::greater
. И этот функтор имеет operator()
объявленный следующим образом:
constexpr bool operator()( const T& lhs, const T& rhs ) const;
Обратите внимание на ссылки const. Он связывает элементы, которые необходимо сравнить с ссылками на const. Поэтому ваш собственный operator>
должен быть также корректным.
Если вы должны были вызвать std::sort
с std::less
, ваш operator<
будет производить ту же ошибку, потому что он не const-correct.
Ответ 2
Использование std::sort(vec.begin(), vec.end())
зависит только от operator<
function. Это не требует, чтобы функция могла работать с объектами const
.
std::greater
, с другой стороны, требует, чтобы функция могла работать с объектами const
.
Аналогичная проблема вы увидите, если вы используете std::less
, например std::sort(vec.begin(), vec.end(), std::less<MyStruct>())
.
Сказав это, нет никаких причин, по которым operator<
функция и operator>
функциями non- const
. Любая функция член, не изменяет данные члены должны быть выполнены в const
функции члена.