Le fait de rendre par défaut <=>
donne automatiquement ==, !=, <, >, <=, >=
gratuitement
C++20 a une nouvelle fonctionnalité de "comparaison par défaut" configurée de telle sorte que le fait de définir par défaut <=>
donne toutes les autres gratuitement. Je crois que c'est la principale motivation derrière l'ajout de operator<=>
.
Adapté de https://en.cppreference.com/w/cpp/language/default_comparisons:
main.cpp
#include
#include
#include
struct Point {
int x;
int y;
auto operator<=>(const Point&) const = default;
};
int main() {
Point pt1{1, 1}, pt2{1, 2};
// Juste pour montrer que cela suffit pour `std::set`.
std::set s;
s.insert(pt1);
// Toutes ces comparaisons sont automatiquement définies pour nous!
assert(!(pt1 == pt2));
assert( (pt1 != pt2));
assert( (pt1 < pt2));
assert( (pt1 <= pt2));
assert(!(pt1 > pt2));
assert(!(pt1 >= pt2));
}
compiler et exécuter:
sudo apt install g++-10
g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Une version équivalente plus explicite de ce qui précède serait:
struct Point {
int x;
int y;
auto operator<=>(const Point& other) const {
if (x < other.x) return -1;
if (x > other.x) return 1;
if (y < other.y) return -1;
if (y > other.y) return 1;
return 0;
}
bool operator==(const Point& other) const = default;
};
Dans ce cas, nous devons définir explicitement bool operator==(const Point& other) const = default;
car si operator<=>
n'est pas défini par défaut (par exemple, comme donné explicitement ci-dessus), alors operator==
n'est pas automatiquement défini:
Conformément aux règles de surcharge de n'importe quel operator<=>
, une surcharge de <=>
définie par défaut permettra également de comparer le type avec <
, <=
, >
, et >=
.
Si operator<=>
est défini par défaut et que operator==
n'est pas du tout déclaré, alors operator==
est implicitement défini par défaut.
L'exemple ci-dessus utilise le même algorithme que le operator<=>
par défaut, tel qu'expliqué par cppreference:
Le operator<=>
par défaut effectue une comparaison lexicographique en comparant successivement les sous-objets de T de base (en profondeur de gauche à droite) puis non statiques (dans l'ordre de déclaration) pour calculer <=>, en étendant récursivement les membres du tableau (dans l'ordre d'index croissant), et s'arrêtant prématurément lorsqu'un résultat de non-égalité est trouvé
Avant C++20, vous ne pouviez pas faire quelque chose comme operator== = default
, et définir un opérateur ne conduirait pas à la définition des autres, par exemple, ce qui suit ne compile pas avec -std=c++17
:
#include
struct Point {
int x;
int y;
auto operator==(const Point& other) const {
return x == other.x && y == other.y;
};
};
int main() {
Point pt1{1, 1}, pt2{1, 2};
// Faire quelques vérifications.
assert(!(pt1 == pt2));
assert( (pt1 != pt2));
}
avec l'erreur:
main.cpp:16:18: erreur : pas de correspondance pour ‘operator!=’ (les types d'opérandes sont ‘Point’ et ‘Point’)
16 | assert( (pt1 != pt2));
| ~~~ ^~ ~~~
| | |
| Point Point
Cependant, ce qui précède compile sous -std=c++20
.
Lié : Les surcharges d'opérateurs C++ sont-elles automatiquement fournies en fonction des autres?
Testé sur Ubuntu 20.04, GCC 10.2.0.
1 votes
@cubuspl42
bar< foo::operator<=>
est un exemple de comment cela pourrait ressembler à l'opérateur<--
.9 votes
@haccks: Tout à fait. Comme C++11 est une étiquette sur les compilateurs qui implémentent C++11. Et C++14 est une étiquette sur les compilateurs qui implémentent C++14. Et C++17 concerne les compilateurs qui implémentent C++17. Non, le C++20 est l'étiquette pour les éléments concernant le C++20. Et comme cette question concerne le C++20, le voici. Le wiki de l'étiquette était incorrect, pas l'étiquette elle-même.