c++ - ¿Por qué se requiere const para 'operador>' pero no para 'operador<'?




sorting operator-overloading (2)

Considere esta pieza de código:

#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;
    }
}

Se compila bien y da el resultado que cabría esperar. Pero si trato de ordenar las estructuras en orden descendente:

#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;
    }
}

Esto me da un error. Aquí está el mensaje completo :

/usr/include/c++/7.2.0/bits/stl_function.h: en la instanciación de 'constexpr bool std :: Greater <_Tp> :: operator () (const _Tp &, const _Tp &) const [with _Tp = MyStruct]' :
/usr/include/c++/7.2.0/bits/stl_function.h:376:20: error: no coincide con 'operator>' (los tipos de operando son 'const MyStruct' y 'const MyStruct')
{return __x> __y; }

Parece ser porque esta función aquí no tiene un calificador const :

bool operator > (const MyStruct& other) {
        return (key > other.key);
}

Si lo agrego,

bool operator > (const MyStruct& other) const {
        return (key > other.key);
}

Entonces todo vuelve a estar bien. ¿Por qué esto es tan? No estoy muy familiarizado con la sobrecarga del operador, así que lo acabo de guardar en la memoria para que necesitemos agregar la const pero aún es extraño por qué funciona para el operator< sin la const .


El uso de std::sort(vec.begin(), vec.end()) depende solo de la función del operator< . No requiere que la función pueda trabajar con objetos const .

std::greater , por otro lado, requiere que la función pueda trabajar con objetos const .

Verá un problema similar si usa std::less , como std::sort(vec.begin(), vec.end(), std::less<MyStruct>()) .

Dicho esto, no hay razón para que la función operator< función y la función operator> sean funciones miembro no const . Cualquier función miembro que no modifique los datos del miembro debe convertirse en una función miembro const .


Obtiene comportamientos diferentes porque de hecho está llamando a dos funciones de sort diferentes (sobrecargadas).

En el primer caso, llama a los dos parámetros std::sort , que usa el operator< directamente. Dado que los iteradores de sus elementos vectoriales producen referencias no constantes, puede aplicar el operator< muy bien.

En el segundo caso, está utilizando la versión de tres parámetros de std::sort . El que acepta un functor. Usted pasa std::greater . Y ese functor tiene un operator() declarado de la siguiente manera:

constexpr bool operator()( const T& lhs, const T& rhs ) const;

Tenga en cuenta las referencias constantes. Vincula los elementos que necesita comparar con las referencias constantes. Por lo tanto, su propio operator> debe ser constante.

Si std::sort llamar a std::sort con std::less , su operator< producirá el mismo error, porque no es constante.





operator-overloading