En comparant deux instances de la structure suivante, je reçois une erreur:
struct MyStruct1 {
MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
my_struct_2(_my_struct_2),
an_int(_an_int)
{}
std::string toString() const;
MyStruct2 my_struct_2;
int an_int;
};
L'erreur est:
erreur C2678: binaire '==': aucun opérateur trouvé qui prend un opérande de gauche de type 'myproj :: MyStruct1' (ou il n'y a pas de conversion acceptable)
Pourquoi?
c++
struct
comparison-operators
Jonathan
la source
la source
struct
s pour l'égalité? Et si vous voulez la manière simple, il y a toujoursmemcmp
tellement longtemps que vos structures ne contiennent pas de pointeur.memcmp
échoue avec les membres non-POD (commestd::string
) et les structures rembourrées.==
opérateur --- avec une sémantique qui n'est presque jamais ce que l'on veut. (Et ils ne fournissent pas un moyen de le remplacer, vous finissez donc par devoir utiliser une fonction membre). Les langages «modernes» que je connais ne fournissent pas non plus de sémantique de valeur, vous êtes donc obligé d'utiliser des pointeurs, même lorsqu'ils ne sont pas appropriés.operator=
(même s'il fait souvent la mauvaise chose), pour des raisons de compatibilité C.operator==
Cependant, la compatibilité C ne nécessite pas de fichier . Globalement, je préfère ce que fait C ++ à ce que fait Java. (Je ne connais pas C #, alors peut-être que c'est mieux.)= default
!C ++ 20 a introduit des comparaisons par défaut, alias le "vaisseau spatial"
operator<=>
, qui vous permet de demander des opérateurs<
/<=
/==
/!=
/>=
/ et / ou générés par le compilateur>
avec l'implémentation évidente / naïve (?) ...... mais vous pouvez personnaliser cela pour des situations plus compliquées (voir ci-dessous). Voir ici la proposition de langue, qui contient des justifications et des discussions. Cette réponse reste pertinente pour C ++ 17 et versions antérieures, et pour savoir quand vous devez personnaliser l'implémentation de
operator<=>
....Cela peut sembler un peu inutile de C ++ de ne pas l'avoir déjà standardisé plus tôt, mais les structures / classes ont souvent des données membres à exclure de la comparaison (par exemple, les compteurs, les résultats mis en cache, la capacité du conteneur, le code de réussite de la dernière opération / erreur, les curseurs), comme ainsi que des décisions à prendre sur une myriade de choses, y compris mais sans s'y limiter:
int
membre particulier peut éliminer très rapidement 99% des objets inégaux, tandis qu'unmap<string,string>
membre peut souvent avoir des entrées identiques et être relativement coûteux à comparer - si les valeurs sont chargées à l'exécution, le programmeur peut avoir des informations sur le le compilateur ne peut pasvector
,list
), et si oui, s'il est correct de les trier sur place avant de comparer ou d'utiliser de la mémoire supplémentaire pour trier les temporaires chaque fois qu'une comparaison est effectuéeunion
compareroperator==
eux-mêmes (mais qui pourraient avoircompare()
ouoperator<
oustr()
ou getters ...)Donc, c'est plutôt bien d'avoir une erreur jusqu'à ce que vous ayez explicitement réfléchi à ce que la comparaison devrait signifier pour votre structure spécifique, plutôt que de la laisser compiler mais pas de vous donner un résultat significatif au moment de l'exécution .
Cela dit, ce serait bien si C ++ vous laisse dire
bool operator==() const = default;
quand vous avez décidé qu'un==
test membre par membre "naïf" était acceptable. Pareil pour!=
. Compte tenu de plusieurs membres / bases, « default »<
,<=
,>
, et>=
mises en œuvre semblent sans espoir que - en cascade sur la base de l' ordre de de déclaration possible , mais très peu de chances d'être ce qui a voulu, compte tenu des impératifs contradictoires pour la commande des membres (bases étant nécessairement avant que les membres, le regroupement par accessibilité, construction / destruction avant utilisation dépendante). Pour être plus largement utile, C ++ aurait besoin d'un nouveau système d'annotation de membre de données / base pour guider les choix - ce serait une bonne chose à avoir dans le Standard, idéalement couplé à la génération de code défini par l'utilisateur basé sur AST ... il'Implémentation typique des opérateurs d'égalité
Une mise en œuvre plausible
Il est probable qu'une mise en œuvre raisonnable et efficace serait:
Notez que cela nécessite un
operator==
pourMyStruct2
aussi.Les implications de cette implémentation et des alternatives sont discutées sous la rubrique Discussion des spécificités de votre MyStruct1 ci-dessous.
Une approche cohérente de ==, <,> <= etc
Il est facile de tirer parti
std::tuple
des opérateurs de comparaison pour comparer vos propres instances de classe - utilisez simplementstd::tie
pour créer des tuples de références aux champs dans l'ordre de comparaison souhaité. Généraliser mon exemple à partir d' ici :Lorsque vous "possédez" (c'est-à-dire que vous pouvez éditer un facteur avec les bibliothèques d'entreprise et tierces) la classe que vous voulez comparer, et en particulier avec la préparation de C ++ 14 à déduire le type de retour de fonction de l'
return
instruction, il est souvent plus agréable d'ajouter un " liez "la fonction membre à la classe que vous voulez pouvoir comparer:Ensuite, les comparaisons ci-dessus se simplifient en:
Si vous voulez un ensemble plus complet d'opérateurs de comparaison, je suggère des opérateurs de boost (recherche de
less_than_comparable
). Si cela ne convient pas pour une raison quelconque, vous pouvez ou non aimer l'idée de macros de support (en ligne) :... qui peut ensuite être utilisé à la ...
(Version C ++ 14 membres-tie ici )
Discussion sur les spécificités de votre MyStruct1
Il y a des implications au choix de fournir un indépendant plutôt qu'un membre
operator==()
...Mise en œuvre autonome
Vous avez une décision intéressante à prendre. Comme votre classe peut être implicitement construite à partir de a
MyStruct2
, une fonction autonome / non membrebool operator==(const MyStruct2& lhs, const MyStruct2& rhs)
prendrait en charge ...... en créant d' abord temporaire à
MyStruct1
partirmy_myStruct2
, puis en faisant la comparaison. Cela laisserait définitivementMyStruct1::an_int
la valeur de paramètre par défaut du constructeur de-1
. Selon que vous incluezan_int
comparaison dans la mise en œuvre de votreoperator==
, unMyStruct1
pourrait ou non être égaux à unMyStruct2
qui se compare égal auMyStruct1
demy_struct_2
membre! En outre, la création d'un temporaireMyStruct1
peut être une opération très inefficace, car elle implique de copier lemy_struct2
membre existant dans un temporaire, uniquement pour le jeter après la comparaison. (Bien sûr, vous pouvez empêcher cette construction implicite deMyStruct1
s pour la comparaison en créant ce constructeurexplicit
ou en supprimant la valeur par défaut dean_int
.)Implémentation des membres
Si vous souhaitez éviter la construction implicite de a à
MyStruct1
partir de aMyStruct2
, faites de l'opérateur de comparaison une fonction membre:Notez que le
const
mot-clé - uniquement nécessaire pour l'implémentation du membre - informe le compilateur que la comparaison d'objets ne les modifie pas, donc peut être autorisée sur lesconst
objets.Comparaison des représentations visibles
Parfois, le moyen le plus simple d'obtenir le type de comparaison que vous souhaitez peut être ...
... ce qui est souvent très cher aussi - ceux qui ont été
string
créés douloureusement juste pour être jetés! Pour les types avec des valeurs à virgule flottante, la comparaison des représentations visibles signifie que le nombre de chiffres affichés détermine la tolérance dans laquelle des valeurs presque égales sont traitées comme égales lors de la comparaison.la source
int cmp(x, y)
oucompare
fonction renvoyant une valeur négative pourx < y
, 0 pour l' égalité et une valeur positive pourx > y
est utilisée comme base pour<
,>
,<=
,>=
,==
et!=
; il est très facile d'utiliser le CRTP pour injecter tous ces opérateurs dans une classe. Je suis sûr que j'ai publié la mise en œuvre dans une ancienne réponse, mais je n'ai pas pu la trouver rapidement.>
,<=
et>=
en termes de<
. Vous pouvez également mettre en œuvre==
et de!=
cette façon, mais ce ne serait généralement pas une mise en œuvre très efficace, je suppose. Ce serait bien si aucun CRTP ou autre astuce ne serait nécessaire pour tout cela, mais la norme exigerait simplement la génération automatique de ces opérateurs si elle n'est pas explicitement définie par l'utilisateur et<
est définie.==
et!=
peut ne pas être efficacement exprimé en utilisant<
que l'utilisation de comparer pour tout est courante. « Ce serait bien si aucun CRTP ou d' autres tours seraient nécessaires » - peut - être, mais CRTP peut facilement être utilisé pour générer beaucoup d'autres opérateurs (par exemple au niveau du bit|
,&
,^
de|=
,&=
et^=
,+
-
*
/
%
de leurs formes d'affectation, binaire-
de la négation unaire et+
) - tellement de variations potentiellement utiles sur ce thème que le simple fait de fournir une fonctionnalité de langage pour une tranche assez arbitraire de ce thème n'est pas particulièrement élégant.std::tie
pour faire la comparaison de plusieurs membres?Vous devez définir explicitement
operator ==
pourMyStruct1
.Désormais, la comparaison == est légale pour 2 de ces objets.
la source
A partir de C ++ 20, il devrait être possible d'ajouter un ensemble complet d'opérateurs de comparaison par défaut (
==
,<=
, etc.) à une classe en déclarant un défaut opérateur de comparaison à trois voies (opérateur « vaisseau spatial »), comme ceci:Avec un compilateur C ++ 20 conforme, l'ajout de cette ligne à MyStruct1 et MyStruct2 peut être suffisant pour permettre des comparaisons d'égalité, en supposant que la définition de MyStruct2 est compatible.
la source
La comparaison ne fonctionne pas sur les structures en C ou C ++. Comparez plutôt par champs.
la source
Par défaut, les structures n'ont pas d'
==
opérateur. Vous devrez écrire votre propre implémentation:la source
Hors de la boîte, l'opérateur == ne fonctionne que pour les primitives. Pour que votre code fonctionne, vous devez surcharger l'opérateur == pour votre structure.
la source
Parce que vous n'avez pas écrit d'opérateur de comparaison pour votre structure. Le compilateur ne le génère pas pour vous, donc si vous voulez une comparaison, vous devez l'écrire vous-même.
la source