web-dev-qa-db-fra.com

En quoi l'opérateur de comparaison à trois voies est-il différent de la soustraction?

Il y a un nouvel opérateur de comparaison <=> en C++ 20. Cependant, je pense que dans la plupart des cas, une simple soustraction fonctionne bien:

int my_strcmp(const char *a, const char *b) {
    while (*a == *b && *a != 0 && *b != 0) {
        a++, b++;
    }
    // Version 1
    return *a - *b;
    // Version 2
    return *a <=> *b;
    // Version 3
    return ((*a > *b) - (*a < *b));
}

Ils ont le même effet. Je ne peux pas vraiment comprendre la différence.

50
iBug

L’opérateur résout le problème de dépassement numérique que vous obtenez avec la soustraction: si vous soustrayez un grand nombre positif d’un négatif qui est proche de INT_MIN, vous obtenez un nombre qui ne peut pas être représenté par un int, ce qui provoque un comportement indéfini.

Bien que la version 3 soit exempte de ce problème, elle manque totalement de lisibilité: il faudrait un certain temps pour la comprendre de la part de quelqu'un qui n'a jamais vu cette astuce auparavant. <=> l'opérateur résout également le problème de lisibilité.

Ce n'est qu'un problème abordé par le nouvel opérateur. La section 2.2.3 de Herb Sutter's Comparaison cohérente papier parle de l'utilisation de <=> avec d'autres types de données du langage où la soustraction peut produire des résultats incohérents.

52
dasblinkenlight

Voici quelques cas pour lesquels la soustraction ne fonctionnera pas:

  1. unsigned types.
  2. Opérandes provoquant un dépassement d'entier.
  3. Types définis par l'utilisateur qui ne définissent pas operator - _ (peut-être parce que cela n’a pas de sens - on peut définir un ordre sans définir une notion de distance).

Je soupçonne que cette liste est non exhaustive.

Bien sûr, on peut trouver des solutions de contournement pour les n ° 1 et n ° 2 au moins. Mais l'intention de operator <=> est d’encapsuler cette laideur.

40
Oliver Charlesworth

Il y a quelques réponses significatives ici sur la différence, mais Herb Sutter dans son article dit spécifiquement:

<=> est destiné aux personnes qui implémentent le type: le code utilisateur (y compris le code générique) en dehors de la mise en oeuvre d'un opérateur <=> ne devrait presque jamais invoquer un <=> directement (comme cela a déjà été découvert comme une bonne pratique dans d'autres langues);

Donc, même s'il n'y avait pas de différence, le point de l'opérateur est différent: aider les rédacteurs de classe à générer des opérateurs de comparaison.

La différence fondamentale entre l'opérateur de soustraction et l'opérateur "vaisseau spatial" (selon la proposition de Sutter) est que la surcharge operator- Vous donne un opérateur de soustraction, alors que la surcharge operator<=>:

  • vous donne les 6 opérateurs de comparaison principaux (même si vous déclarez l'opérateur comme default: pas de code à écrire!);
  • déclare si votre classe est comparable, peut être triée et si l'ordre est total ou partiel (fort/faible dans la proposition de Sutter);
  • permet des comparaisons hétérogènes: vous pouvez le surcharger pour comparer votre classe à n’importe quel autre type.

Les autres différences sont dans la valeur de retour: operator<=> Renverrait un enum d'une classe. La classe spécifie si le type est triable et si le tri est fort ou faible. La valeur de retour serait convertie en -1, 0 ou 1 (bien que Sutter laisse de la place au type de retour pour indiquer également la distance, comme le fait strcmp.). Dans tous les cas, en supposant que la valeur de retour soit -1, 0, 1, nous aurons finalement ne vraie fonction de signum en C++ ! (signum(x) == x<=>0)

16
Cris Luengo