Considérons 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 le résultat attendu. 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: en instanciation de 'constexpr bool std :: supérieur <_Tp> :: operator () (const _Tp &, const _Tp &) const [avec _Tp = MyStruct]' :
/usr/include/c ++/7.2.0/bits/stl_function.h: 376: 20: erreur: pas de correspondance pour 'opérateur>' (les types d'opérande sont 'const MyStruct' et 'const MyStruct')
{return __x> __y; }
Cela semble être dû au fait que cette fonction ici n’a pas de qualificatif const
:
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 bien à nouveau. Pourquoi cela est-il ainsi? Je ne connais pas trop la surcharge d'opérateur, je viens donc de le mettre en mémoire. Nous devons donc ajouter le const
, mais c'est toujours étrange pourquoi cela fonctionne pour operator<
sans le const
.
Vous obtenez des comportements différents parce que vous appelez en fait deux fonctions différentes (surchargées) sort .
Dans le premier cas, vous appelez les deux paramètres std::sort
, Qui utilisent directement operator<
. Etant donné que les itérateurs de vos éléments vectoriels produisent des références non constantes, cela peut très bien s'appliquer operator<
.
Dans le second cas, vous utilisez la version à trois paramètres de std::sort
. Celui qui accepte un foncteur. Vous passez std::greater
. Et ce foncteur a une operator()
déclarée comme suit:
constexpr bool operator()( const T& lhs, const T& rhs ) const;
Notez les références const. Il lie les éléments à comparer aux références const. Donc, votre propre operator>
Doit également être correct.
Si vous appeliez std::sort
Avec std::less
, votre operator<
Produirait la même erreur, car ce n'est pas const-correct.
L'utilisation de std::sort(vec.begin(), vec.end())
ne dépend que de la fonction operator<
. Il n'est pas nécessaire que la fonction puisse fonctionner avec les objets const
.
std::greater
, En revanche, nécessite que la fonction puisse fonctionner avec les objets const
.
Vous verrez un problème similaire si vous utilisez std::less
, Tel que std::sort(vec.begin(), vec.end(), std::less<MyStruct>())
.
Cela dit, il n'y a aucune raison pour que la fonction operator<
Et la fonction operator>
Soient des fonctions non -const
member. Toute fonction membre qui ne modifie pas les données de membre doit devenir une fonction membre const
.