51 votes

Pourrais-je utiliser l'opérateur == si j'ai seulement implémenté l'opérateur <?

J'ai implémenté operator< pour un certain objet. Logiquement, si !(a < b) et !(b < a) cela signifie que a == b.

Est-ce que cela est déduit automatiquement ? Puis-je utiliser == si j'ai seulement implémenté < ?

69voto

Le langage C++ ne peut pas déduire cela automatiquement pour plusieurs raisons :

  1. Cela n'a pas de sens pour chaque type d'être comparé avec operator<, donc le type peut ne pas nécessairement définir un operator<.
    • Cela signifie que operator== ne peut pas être automatiquement défini en termes de operator<
  2. operator< n'est pas nécessaire pour comparer ses arguments. Un programmeur peut définir des opérateurs pour leurs types afin de faire presque tout à leurs arguments.
    • Cela signifie que votre affirmation selon laquelle !(a < b) && !(b < a) est équivalent à a == b ne soit pas nécessairement vrai, en supposant que ces opérateurs soient définis.

Si vous souhaitez une fonction operator== pour vos types, il suffit de la définir vous-même. Ce n'est pas si difficile :)

// Pour la comparaison, quelque chose comme ceci est utilisé
bool operator==(const MyType& lhs, const MyType& rhs)
{
    // comparez (ou faites d'autres actions!) comme vous le souhaitez
}

// ... bien que ce ne soit pas la seule chose que vous puissiez faire
//  - Le type de retour peut être personnalisé
//  - ... tout comme les deux arguments
const MyType& operator==(int* lhs, const MyType* const rhs)
{
    return lhs;
}

47voto

Lưu Vĩnh Phúc Points 3183

Il ne peut pas déduire == à partir de < car tous les types ne sont pas ordonnés, comme std::complex. Est-ce que 2 + 3i > 1 + 4i ou non?

De plus, même dans les types normalement ordonnés, vous ne pouvez pas déduire l'égalité à partir de > ou <, par exemple IEEE-754 NaN

double n = std::numeric_limits::quiet_NaN();

std::cout << "NaN == NaN: " << (n == n) << '\n';
std::cout << "NaN < NaN: " << (n < n) << '\n';
std::cout << "NaN > NaN: " << (n > n) << '\n';
std::cout << "NaN != NaN: " << (n != n) << '\n';

Ils renverront tous false à l'exception du dernier

18voto

Shitao Zhou Points 181

Non. Cette méthode fonctionne bien sur des objets semblables à des nombres appelés totalement ordonnés. Pour tous types de ensembles/classes, personne ne peut garantir cette relation. Même personne ne peut garantir qu'un opérateur < comparerait quelque chose.

Donc == n'est rien d'autre que ==. Vous pouvez implémenter == par < mais cela ne fonctionne pas pour tout le monde et les normes C++ ne le feront pas pour vous.

12voto

Jonas Points 5829

C++ ne déduit pas cela automatiquement. Pour operator>, operator<= et operator>=, vous pourriez utiliser std::rel_ops; cela ne nécessite que operator<. Cependant, cela ne fournit pas operator== en termes de operator<. Vous pouvez le faire vous-même comme ceci :

template 
bool operator==(T const& lhs, T const& rhs)
{
    return !((lhs < rhs) or (rhs < lhs));
}

Remarquez que : !((lhs < rhs) or (rhs < lhs)) et !(lhs < rhs) and !(rhs < lhs) sont équivalents, mathématiquement.

12voto

Arne Vogel Points 506

Logiquement, si !(a < b) et !(b < a) cela signifie que a == b. C++ l'infère-t-il automatiquement ? Puis-je utiliser == si je n'ai implémenté que

Pour exprimer ce que d'autres ont déclaré en termes mathématiques : En supposant que vous ayez un operator < qui retourne bool et définit un ordre strict faible, et que vous implémentiez operator == en retournant !(a < b) && !(b < a), alors cet opérateur définit une relation d'équivalence cohérente avec l'ordre strict faible donné. Cependant, C++ ne requiert pas que operator < définisse un ordre strict faible, ni que operator == définisse une relation d'équivalence (bien que de nombreux algorithmes standard tels que sort utilisent implicitement ces opérateurs et requièrent un ordre strict faible ou une relation d'équivalence).

Si vous souhaitez définir tous les autres opérateurs relationnels en fonction de l'ordre strict faible de votre operator < et de manière cohérente avec celui-ci, Boost.Operators pourrait vous faire gagner du temps.

Étant donné qu'il est si facile de mal utiliser un operator < qui ne répond pas aux exigences des algorithmes standard, par exemple en l'utilisant accidentellement via std::sort, std::lower_bound, etc., je recommande de définir operator < soit comme un ordre strict faible, soit de ne pas le définir du tout. L'exemple donné par CodesInChaos est un ordre partiel, qui ne satisfait pas l'exigence de "transitivité de l'incomparabilité" d'un ordre strict faible. Par conséquent, je recommande d'appeler une telle relation par un autre nom, par exemple bool setLess(const MySet &, const MySet &).

Sources:

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