Question

Je vais avoir un comportement étrange avec un opérateur surcharge en C ++. J'ai une classe, et je dois vérifier si son contenu est supérieur ou égal à un long double. Je l'surchargée> = pour faire cette vérification, ma déclaration est la suivante:

bool MyClass::operator>=(long double value) const;

Je dois dire que j'ai aussi un casting à long double opérateur pour ma classe, qui fonctionne sans exceptions que dans certaines conditions. Maintenant, quand j'utilise cet opérateur, le compilateur se plaint qu'il ya une utilisation ambiguë de l'opérateur> = et les alternatives sont:

  • mine.
  • Le haut-operator>=(long double, int).

Maintenant, comment puis-je forcer le programme à utiliser mon opérateur?

Était-ce utile?

La solution

2015 mise à jour: Ou, si vous voulez conserver la capacité de conversion en utilisant la syntaxe de la place (double)obj la syntaxe obj.to_double(), faire la fonction de conversion explicit en préfixant avec ce mot-clé. Vous avez besoin d'un casting explicite alors pour la conversion à déclencher. Personnellement, je préfère la syntaxe .to_double, à moins que la conversion serait de bool parce que dans ce cas, la conversion est utilisé par if(obj) même si elle est explicit, et qui est beaucoup plus lisible que if(obj.to_bool()) à mon avis.


Laissez tomber l'opérateur de conversion. Il causera des problèmes tout le chemin. Avoir une fonction comme

to_double()

Ou similaire qui retourne la valeur double et appeler explicitement cette fonction pour obtenir un double.

Pour le problème à portée de main, il y a ce problème:

obj >= 10

Pensez à cette expression. L'opérateur correspond au premier builtin argument une séquence de conversion définie par l'utilisateur pour votre type en utilisant l'opérateur de conversion long double (). Mais votre fonction correspond au second argument par une séquence de conversion standard de int à long double (partie intégrante de la conversion en virgule flottante). Il est toujours ambigu quand il y a des conversions pour deux arguments, mais pas au moins un argument qui peut être converti mieux alors que les autres arguments ne sont pas convertis pire pour un appel. Dans votre cas, celui builtin correspond au second argument, mais mieux le premier pire, mais votre fonction correspond au premier argument, mais mieux la deuxième pire.

Il est source de confusion, alors voici quelques exemples (conversions de char int sont appelés les promotions, qui sont mieux que les conversions de char à autre chose que int, qui est appelé une conversion):

void f(int, int);
void f(long, long);
f('a', 'a');

Appelle la première version. Parce que tous les arguments pour la première peuvent être convertis mieux. De même, ce qui suit toujours appeler le premier:

void f(int, long);
void f(long, long);
f('a', 'a');

Parce que la première peut être convertie mieux, et le second est pas convertie pire. Mais ce qui suit est ambigu :

void f(char, long);
void f(int, char);
f('a', 'a'); // ambiguous

Il est plus intéressant dans ce cas. La première version accepte le premier argument par une correspondance exacte. La deuxième version accepte le second argument par une correspondance exacte. Mais les deux versions n'acceptent pas leur autre argument au moins aussi bien. La première version nécessite une conversion pour son deuxième argument, alors que la deuxième version nécessite une promotion pour son argument. Ainsi, même si une promotion est mieux qu'une conversion, l'appel à la deuxième version échoue.

Il est très proche de votre cas ci-dessus. Même si une séquence de conversion standard (conversion de int / flotteur / double pour long double) est mieux d'une séquence de conversion définie par l'utilisateur (conversion de MyClass à long double), votre version de l'opérateur n'a pas été choisi, parce que votre autre paramètre (long double) nécessite une conversion de l'argument qui est pire que ce que l'opérateur a besoin pour builtin cet argument (match parfait).

Résolution de surcharge est une question complexe en C ++, donc on peut se souvenir impossiblement toutes les règles subtiles en elle. Mais obtenir le plan approximatif est tout à fait possible. J'espère que cela vous aide.

Autres conseils

En fournissant une conversion implicite à un double vous efficacement énoncez, ma classe est équivalente à une double et pour cette raison vous ne devriez pas vraiment l'esprit si le construit dans l'opérateur> = pour doubles est utilisé. Si vous faire soins, votre classe est vraiment pas « équivalent » à un double et vous devriez considérer ne pas fournir une implicite conversion à double, mais plutôt fournir un explicite GetAsDouble, ou la fonction de membre ConvertToDouble.

La raison pour laquelle vous avez une ambiguïté au moment est que pour une expression t >= dt est une instance de votre classe et d est un double, le compilateur doit toujours fournir une conversion soit du côté gauche ou droit côté si l'expression est vraiment ambigu. Soit le t de operator double est appelée et intégré dans l'opérateur> = pour doubles est utilisé, ou d doit être promu à un long double et votre opérateur membre> = est utilisé.

Modifier, vous avez mis à jour votre question pour suggérer que votre conversion est un long double et votre comparaison est contre un int. Dans ce cas, le dernier paragraphe:

La raison pour laquelle vous avez une ambiguïté au moment est que pour une expression t >= dt est une instance de votre classe et d est un int, le compilateur doit toujours fournir une conversion soit du côté gauche ou droit côté si l'expression est vraiment ambigu. est appelée et le haut-opérateur> = pour t et operator long double est utilisé, ou d doit être promu à un long double et votre opérateur membre> = est utilisé le int de long double soit.

Je suppose que vous comparez contre un int littéral, et non un long double:

MyClass o;

if (o >= 42)
{
   // ...
}

Si tel est le cas, les deux alternatives sont aussi bons / complexes.

Utilisation de votre operator long double():

  1. MyClass::operator long double()
  2. intégré operator>=(long double, int)

Utilisation de votre MyClass::operator>=(long double):

  1. intégré conversion int à long double
  2. MyClass::operator>=(long double)

Vous avez long double dans la déclaration. Essayez de changer à double.

Votre utilisation de l'opérateur surcharge combinée avec la coulée personnalisée peut être très déroutant pour les utilisateurs de votre classe. Demandez-vous, les utilisateurs seraient de cette classe attendre pour se convertir en un double, ou être comparable à un double? N'ayant une fonction .greaterThan (double) atteindre le même objectif, mais sans surprendre l'utilisateur?

Je suppose que vous pouvez toujours jeter explicitement votre objet à doubler avant de comparer, pour éviter l'ambiguïté. Mais si je vous je reconsidère l'approche ci-dessus et de se concentrer sur le code d'écriture qui est intuitive et se comporte d'une manière sans surprise, au lieu de type coulée de fantaisie et de surcharge opérateur.

(Inspiré merveilleux au sujet de la surcharge d'opérateur )

  • Le haut-opérateur> = (long double, int).

On dirait que vous avez défini:

bool class::operator>=(long double value) { return value >= classValue; }

Et vous manque:

bool class::operator>=(double value)      { return value >= classValue; }
bool class::operator>=(int value)         { return value >= classValue; }

Ainsi, le compilateur ne peut pas décider quel moyen de convertir. (Il est ambigu.)

Peut-être une fonction basé sur un modèle (ou méthode) serait utile?

Attention aux situations où a> = b invoque différentes méthodes que b> = a .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top