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é <
?
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é <
?
Le langage C++ ne peut pas déduire cela automatiquement pour plusieurs raisons :
operator<
, donc le type peut ne pas nécessairement définir un operator<
.
operator==
ne peut pas être automatiquement défini en termes de operator<
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.
!(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;
}
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
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.
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.
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 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.