142 votes

Pourquoi l'inégalité est-elle testée comme (! (A == b)) dans beaucoup de code de bibliothèque standard C ++?

C'est le code de la bibliothèque standard C ++ remove code. Pourquoi l'inégalité est-elle testée en if (!(*first == val)) au lieu de if (*first != val) ?

  template <class ForwardIterator, class T>
      ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
 {
     ForwardIterator result = first;
     while (first!=last) {
         if (!(*first == val)) {
             *result = *first;
             ++result;
         }
         ++first;
     }
     return result;
 }
 

144voto

Tom Tanner Points 4148

Parce que cela signifie que la seule exigence sur T est d'implémenter un operator== . Vous pourriez demander à T d'avoir un operator!= mais l'idée générale ici est que vous devriez mettre le moins de fardeau possible sur l'utilisateur du template et que d'autres templates ont besoin de operator== .

36voto

La plupart des fonctions dans la STL travailler uniquement avec des operator< ou operator==. Cela exige de l'utilisateur qu'à la mise en œuvre de ces deux opérateurs (ou, parfois, au moins l'un d'entre eux). Par exemple std::set utilise operator< (plus précisément std::less qui évoque operator< par défaut) et pas operator> pour gérer la commande. L' remove le modèle de votre exemple est un cas similaire, il utilise seulement operator== et pas operator!= si l' operator!= n'a pas besoin d'être défini.

28voto

Christian Hackl Points 4763

C'est le code de la norme C++ de la bibliothèque de supprimer le code.

Mal. Ce n'est pas le C++ standard library remove code. Il est possible internes de mise en œuvre de la norme C++ library remove fonction. La norme C++ ne prescrit pas de code; il prescibes prototypes de fonction et les comportements requis.

En d'autres termes: à Partir d'un langage " strict point de vue, le code que vous voyez n'existe pas. Il peut être de quelques fichier d'en-tête qui vient avec votre compilateur standard-mise en œuvre de bibliothèque. Notez que la norme C++ n'exige même pas ceux de l'en-tête des fichiers d'exister. Les fichiers sont juste un moyen pratique pour le compilateur réalisateurs pour répondre aux exigences d'une ligne comme celle - #include <algorithm> ( std::remove et les autres fonctions disponibles).

Pourquoi l'inégalité testé en tant que if (!(*first == val)) au lieu de if (*first != val) ?

Parce que seulement operator== est requis par la fonction.

Quand il s'agit de la surcharge d'opérateur pour les types personnalisés, la langue vous permet de faire toutes sortes de choses bizarres. Vous pouvez très bien créer une classe qui a surchargé operator== mais pas surchargé operator!=. Ou pire encore: Vous pouvez la surcharge operator!= mais il a de le faire totalement sans rapport avec les choses.

Considérons cet exemple:

#include <algorithm>
#include <vector>

struct Example
{
    int i;

    Example() : i(0) {}

    bool operator==(Example const& other) const
    {
        return i == other.i;
    }

    bool operator!=(Example const& other) const
    {
        return i == 5; // weird, but nothing stops you
                       // from doing so
    }

};

int main()
{
  std::vector<Example> v(10);
  // ...
  auto it = std::remove(v.begin(), v.end(), Example());
  // ...
}

Si std::remove utilisé operator!=, alors le résultat serait tout à fait différent.

15voto

Richard Hodges Points 1972

Quelques bonnes réponses ici. Je voulais juste ajouter une petite note.

Comme toutes les bonnes bibliothèques, la bibliothèque standard est conçu avec (au moins) deux principes très importants à l'esprit:

  1. Mettre le moins de la responsabilité des utilisateurs de votre bibliothèque que vous pouvez sortir avec. Une partie de cela a à voir avec en leur donnant le moins de travail à faire lors de l'utilisation de votre interface. (comme la définition que quelques opérateurs comme vous pouvez vous en sortir avec). L'autre partie de cela a à voir avec ne pas les surprendre ou les obligeant à vérifier les codes d'erreur (donc, gardez interfaces cohérentes et lancer des exceptions <stdexcept> quand les choses vont mal).

  2. Éliminer toutes les logiques de la redondance. Toutes les comparaisons peuvent être déduites à partir du seul operator<, alors pourquoi exiger que les utilisateurs définissent les autres? e.g:

    (a > b) est équivalent à (b < a)

    (a >= b) est équivalent à !(a < b)

    (a == b) est équivalent à !((a < b) || (b < a))

    et ainsi de suite.

    Bien sûr, sur cette note, on peut se demander pourquoi unordered_map exige operator== (au moins par défaut) plutôt que d' operator<. La réponse est que, dans une table de hachage la comparaison ne jamais nous avons besoin l'un de l'égalité. Il est donc plus logiquement cohérentes (c'est à dire plus de sens pour l'utilisateur de la bibliothèque) pour les obliger à définir un opérateur d'égalité. Exigeant une operator< serait source de confusion, car il n'est pas immédiatement évident pourquoi vous auriez besoin.

8voto

Hurkyl Points 1718

La concept exige *seulement* que être définie.

Par conséquent, toute fonction qui veut travailler avec les types satisfaisants *ne saurait* invoquer l’existence de pour les objets de ce type. (sauf s’il existe des exigences supplémentaires qui impliquent l’existence de `` ).

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