59 votes

Pourquoi le paramètre const est-il requis pour "operator>" mais pas pour "operator<" ?

Considérez ce morceau de code :

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

Il compile bien et donne la sortie que l'on attend. Mais si j'essaie de trier les structures par ordre décroissant :

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

Cela me donne une erreur. Voici le message complet :

/usr/include/c++/7.2.0/bits/stl_function.h : Dans l'instanciation 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 match for 'operator>' (operand types are 'const MyStruct' and 'const MyStruct')
{ return __x > __y ; }

Il semble que c'est parce que cette fonction ici n'a pas de const qualificatif :

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

Si je l'ajoute,

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

Ensuite, tout va de nouveau bien. Pourquoi en est-il ainsi ? Je ne suis pas trop familier avec la surcharge d'opérateurs, donc j'ai juste mis en mémoire que nous devons ajouter la fonction const mais c'est toujours bizarre que cela fonctionne pour operator< sans le const .

0 votes

Quel compilateur avez-vous utilisé ? Quelle est sa version ?

0 votes

0 votes

@Rockstart5645 ce qui est de cette pertinence ici ?

85voto

StoryTeller Points 6139

Vous obtenez des comportements différents parce que vous appelez en fait deux différents (surchargés) trier fonctions.

Dans le premier cas, vous appelez les deux paramètres std::sort qui utilise operator< directement. Puisque les itérateurs de vos éléments vectoriels produisent des références non-const, il peut appliquer operator< très bien.

Dans le second cas, vous utilisez la version à trois paramètres de l'option std::sort . Celui qui accepte un foncteur. Vous passez std::greater . Et ce foncteur a un operator() a déclaré ce qui suit :

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

Notez les références const. Il lie les éléments qu'il doit comparer à des références constantes. Ainsi, votre propre operator> doivent être constants et corrects également.

Si vous deviez appeler std::sort con std::less , votre operator< produira la même erreur, car il n'est pas const-correct.

0 votes

Nitpicking : sauf std::less<void> .

25voto

R Sahu Points 24027

Utilisation de std::sort(vec.begin(), vec.end()) ne dépend que de la operator< fonction. Il n'est pas nécessaire que la fonction soit en mesure de travailler avec const objets.

std::greater En revanche, la fonction doit pouvoir fonctionner avec les éléments suivants const objets.

Vous rencontrerez un problème similaire si vous utilisez std::less tels que std::sort(vec.begin(), vec.end(), std::less<MyStruct>()) .


Ceci étant dit, il n'y a aucune raison pour que la operator< et la fonction operator> pour ne pas être une fonction const les fonctions des membres. Toute fonction membre qui ne modifie pas les données d'un membre doit être transformée en une fonction d'accès. const fonction membre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X