296 votes

Est == et != mutuellement dépendants?

Je suis en train d'apprendre à propos de la surcharge d'opérateur en C++, et je vois qu' == et != sont simplement des fonctions spéciales qui peuvent être personnalisés pour les types définis par l'utilisateur. Ma préoccupation est, cependant, pourquoi il y a deux définitions nécessaires? J'ai pensé que si a == b la valeur est true, a != b est automatiquement faux, et vice versa, et il n'y a pas d'autre possibilité, parce que, par définition, a != b est !(a == b). Et je ne pouvais pas imaginer une situation dans laquelle ce n'était pas vrai. Mais peut-être que mon imagination est limitée ou je suis ignorant de quelque chose?

Je sais que je peux définir en termes de l'autre, mais ce n'est pas ce que je demande. Je ne suis pas non plus demander à propos de la distinction entre les objets de comparaison par valeur ou par l'identité. Ou si deux objets de l'égalité et de la non-égalité en même temps (ce n'est certainement pas une option! ces choses sont mutuellement exclusif). Ce que je demande est-ce:

Est-il de toute situation possible à qui poser des questions sur les deux objets étant égales par ailleurs ne font sens, mais que vous demandez à leur sujet n' étant égales par ailleurs n'a pas de sens? (soit à partir de la perspective de l'utilisateur, ou le responsable de l'implémentation du point de vue)

Si cette possibilité n'existe pas, alors pourquoi diable est-ce que C++ ont ces deux opérateurs étant définie comme deux fonctions distinctes?

112voto

shrike Points 3396

Si cette possibilité n'existe pas, alors pourquoi diable est-ce que C++ ont ces deux opérateurs étant définie comme deux fonctions distinctes?

Parce que vous pouvez surcharger, et par la surcharge eux, vous pouvez leur donner un sens totalement différent de leur lieu d'origine.

Prenez, par exemple, l'opérateur <<, à l'origine de l'opération de bits de décalage vers la gauche de l'opérateur, maintenant couramment surchargé comme un opérateur d'insertion, comme en std::cout << something; sens totalement différent de celui d'origine.

Donc, si vous acceptez que le sens d'un opérateur change lorsque vous surcharger, alors il n'y a pas de raison pour empêcher l'utilisateur de donner un sens à l'opérateur == qui n'est pas exactement la négation de l'opérateur !=, même si cela pourrait être source de confusion.

61voto

Trevor Hickey Points 3369

Ma préoccupation est, par contre, pourquoi il y a deux définitions distinctes nécessaires?

Vous n'avez pas à définir à la fois.
Si elles sont mutuellement exclusives, vous pouvez toujours être concis que par la définition d' == et < aux côtés de std::rel_ops

Fom cppreference:

#include <iostream>
#include <utility>

struct Foo {
    int n;
};

bool operator==(const Foo& lhs, const Foo& rhs)
{
    return lhs.n == rhs.n;
}

bool operator<(const Foo& lhs, const Foo& rhs)
{
    return lhs.n < rhs.n;
}

int main()
{
    Foo f1 = {1};
    Foo f2 = {2};
    using namespace std::rel_ops;

    //all work as you would expect
    std::cout << "not equal:     : " << (f1 != f2) << '\n';
    std::cout << "greater:       : " << (f1 > f2) << '\n';
    std::cout << "less equal:    : " << (f1 <= f2) << '\n';
    std::cout << "greater equal: : " << (f1 >= f2) << '\n';
}

Est-il de toute situation possible à poser des questions à propos de deux les objets étant égal à fait logique, mais de poser sur eux de ne pas être l'égalité n'a pas de sens?

Nous associons souvent à ces opérateurs de l'égalité.
Bien que c'est la façon dont ils se comportent sur les types fondamentaux, il n'y a aucune obligation que ce soit leur comportement sur les types de données personnalisés. Vous n'avez même pas à renvoyer un booléen si vous ne souhaitez pas.

J'ai vu des gens de la surcharge des opérateurs de façon bizarre, seulement pour trouver qu'il fait sens pour leur domaine d'application spécifique. Même si l'interface s'affiche pour montrer qu'ils sont mutuellement exclusifs, l'auteur peut vouloir ajouter spécifiques logique interne.

(soit à partir de la perspective de l'utilisateur, ou le responsable de l'implémentation du point de vue)

Je sais que vous voulez un exemple concret,l'
voici donc l'un de l' Attraper framework de test que j'ai pensé était pratique:

template<typename RhsT>
ResultBuilder& operator == ( RhsT const& rhs ) {
    return captureExpression<Internal::IsEqualTo>( rhs );
}

template<typename RhsT>
ResultBuilder& operator != ( RhsT const& rhs ) {
    return captureExpression<Internal::IsNotEqualTo>( rhs );
}

Ces opérateurs sont en train de faire des choses différentes, et il ne serait pas judicieux de définir une méthode comme une !(pas) de l'autre. La raison de ce qui est fait, est de sorte que le cadre pouvez imprimer la comparaison faite. Pour ce faire, il a besoin de saisir le contexte de ce que l'opérateur surchargé a été utilisé.

44voto

Jander Points 1679

Il y a quelques très conventions établies en ce qui (a == b) et (a != b) sont à la fois les faux pas nécessairement opposés. En particulier, en SQL, toute comparaison de la valeur NULL donne NULL, true ou false.

Ce n'est probablement pas une bonne idée de créer de nouveaux exemples de cette si possible, parce que c'est tellement pas intuitif, mais si vous essayez de modèle à une convention existante, il est agréable d'avoir la possibilité de faire vos opérateurs se comporter correctement "" pour ce contexte.

24voto

Centril Points 1529

Je vais répondre à la deuxième partie de votre question, à savoir:

Si cette possibilité n'existe pas, alors pourquoi diable est-ce que C++ ont ces deux opérateurs étant définie comme deux fonctions distinctes?

L'une des raisons pourquoi il est logique de permettre au développeur de surcharge à la fois la performance. Vous pouvez autoriser les optimisations par la mise en œuvre de deux == et !=. Ensuite, x != y pourrait être moins cher que d' !(x == y) . Certains compilateurs peuvent être en mesure d'optimiser pour vous, mais peut-être pas, surtout si vous avez des objets complexes avec beaucoup de ramification impliqués.

Même en Haskell, où les développeurs à tirer des lois et des concepts mathématiques très au sérieux, on est encore autorisé à la surcharge de tant == et /=, comme vous pouvez le voir ici (http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#v:-61--61-):

$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
λ> :i Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
        -- Defined in `GHC.Classes'

Ce serait probablement être considérés comme des micro-optimisation, mais il pourrait être justifié dans certains cas.

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