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 compilateur n'infère pas ==
à partir de <
.
Vous pouvez vérifier cela avec un exemple simple:
#include
struct A {
A(int r):i{r}{}
int i;
};
bool operator<(A const & a1, A const& a2) {
return a1.i < a2.i;
}
int main(int argc, char* argv[]) {
A a1{2};
A a2{3};
if(a1 == a2) {
std::cout << "égal\n";
}
return 0;
}
GCC
vous donne cette erreur:
main.cpp:20:11: erreur: pas de correspondance pour l'opérateur '==' (types d'opérandes sont 'A' et 'A')
if(a1 == a2) {
Il existe des modèles définis dans l'espace de noms std::rel_ops
qui définissent automatiquement les opérateurs manquants.
Cela ne définit pas un opérateur d'égalité basé sur l'opérateur de moins que vous souhaitez.
Cependant, cela reste très utile; si vous définissez l'opérateur de moins que et l'opérateur d'égalité, vous obtiendrez gratuitement les autres opérateurs de comparaison.
Comme beaucoup l'ont affirmé, non vous ne pouvez pas, et non le compilateur ne devrait pas le faire.
Cela ne signifie pas que cela ne devrait pas être facile de passer d'un <
à un ==
et tout le reste.
boost::operators tente de le rendre facile. Utilisez-le et c'est fait.
Si vous voulez le faire vous-même, il ne suffit que d'un peu de code pour réimplémenter ce que boost vous fournit :
namespace utility {
namespace details {
templateusing void_t=void;
templateclass Z, class, class...Ts>
struct can_apply:std::false_type{};
templateclass Z, class...Ts>
struct can_apply>, Ts...>:std::true_type{};
}
templateclass Z, class...Ts>
using can_apply = ::utility::details::can_apply;
}
namespace auto_operators {
template
using less_r = decltype( std::declval() < std::declval() );
template
using can_less = ::utility::can_apply;
struct order_from_less {
template
using enabled = std::enable_if_t<
std::is_base_of{}
&& std::is_base_of{}
&& can_less{},
bool
>;
template
friend enabled
operator>(T const& lhs, U const& rhs) {
return rhs < lhs;
}
template
friend enabled
operator<=(T const& lhs, U const& rhs) {
return !(lhs > rhs);
}
template
friend enabled
operator>=(T const& lhs, U const& rhs) {
return !(lhs < rhs);
}
};
struct equal_from_less:order_from_less {
template
using enabled = std::enable_if_t<
std::is_base_of{}
&& std::is_base_of{}
&& can_less{} && can_less{},
bool
>;
template
friend enabled
operator==(T const& lhs, U const& rhs) {
return !(lhs < rhs) && !(rhs < lhs);
}
template
friend enabled
operator!=(T const& lhs, U const& rhs) {
return !(lhs==rhs);
}
};
}
Le code ci-dessus n'a besoin d'être écrit qu'une fois, ou le code équivalent obtenu depuis #include
boost.
Une fois que vous avez boost, ou le code ci-dessus, c'est aussi simple que quelque chose comme :
struct foo : auto_operators::equal_from_less {
int x;
foo( int in ):x(in) {}
friend bool operator<( foo const& lhs, foo const& rhs ) {
return lhs.x < rhs.x;
}
};
et foo
a maintenant tous les opérateurs de comparaison définis sur lui.
int main() {
foo one{1}, two{2};
std::cout << (one < two) << "\n";
std::cout << (one > two) << "\n";
std::cout << (one == two) << "\n";
std::cout << (one != two) << "\n";
std::cout << (one <= two) << "\n";
std::cout << (one >= two) << "\n";
std::cout << (one == one) << "\n";
std::cout << (one != one) << "\n";
std::cout << (one <= one) << "\n";
std::cout << (one >= one) << "\n";
}
Le but de tout cela est que C++ ne suppose pas, en tant que langage, que <
signifie >
et que >=
et ==
ont tous un sens. Mais vous pouvez écrire une bibliothèque qui vous permet de prendre un type avec <
défini, et en ajoutant une classe de base triviale, tous ces autres opérations définies avec aucun coût d'exécution.
La réponse est NON, vous avez juste besoin d'un test simple
struct MyType{
int value;
};
bool operator < (MyType& a, MyType& b)
{
return a.value < b.value;
}
int main(int argc, char* argv[])
{
MyType a = {3};
MyType b = {4};
if (a == b)
std::cout << "a==b" << std::endl;
if (a < b)
std::cout << "a < b" << std::endl;
}
g++ 4.8.2 se plaint :
main.cpp: Dans la fonction ‘int main(int, char**)’ :
main.cpp:16:11: erreur: aucun correspondance pour ‘operator==’ (les types des opérandes sont ‘MyType’ et ‘MyType’)
Mais il y a quelque chose de similaire qui fonctionne en C++, vérifiez ce c++ concepts:Compare
il dit:
equiv(a, b), une expression équivalente à !comp(a, b) && !comp(b, a)
En plus d'autres réponses,
Le compilateur ne peut même pas déduire !=
à partir de ==
struct MyType
{
int value;
};
bool operator == (const MyType& a, const MyType& b)
{
return a.value == b.value;
}
int main()
{
MyType a = {3};
MyType b = {4};
if (a != b) // (* Erreur de compilation *)
std::cout << "a n'est pas égal à b" << std::endl;
}
Cependant, ce serait bien s'il existait une option pour indiquer au compilateur que le reste des opérateurs rationnels s'appliquent à votre classe.
Il y a, comme expliqué dans certaines réponses dans l'en-tête quelque chose qui peut fournir une telle fonctionnalité. Vous devrez ajouter la ligne suivante au début du main
:
using namespace std::rel_ops;
Cependant, l'utilisation de cette approche est coûteuse et entraînera des ambiguïtés de surcharge un peu partout comme l'a noté JDługosz.
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.