Frage

Ich habe ein seltsames Verhalten mit einem Operator in C ++ Überlastung. Ich habe eine Klasse, und ich muss überprüfen, ob sein Inhalt größer oder gleich einem langen Doppel sind. Ich überlastet die> = Operator diese Prüfung zu machen, meine Erklärung ist wie folgt:

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

Ich muß sagen, dass ich auch eine Besetzung zu Langdoppel Operator für meine Klasse, die nur unter bestimmten Bedingungen ohne Ausnahmen funktioniert. Nun, wenn ich diesen Operator verwenden, der Compiler beschwert sich, dass es eine zweideutige Verwendung von Operator> = und die Alternativen sind:

  • Minen.
  • Der eingebaute in operator>=(long double, int).

Nun, wie erzwinge ich das Programm meinen Bediener zu benutzen?

War es hilfreich?

Lösung

2015 Update: Oder, wenn Sie Conversion-Fähigkeit mit der (double)obj Syntax stattdessen die obj.to_double() Syntax behalten mögen, die Konvertierungsfunktion explicit machen, indem es mit diesem Stichwort prefixing. Sie müssen eine explizite Umwandlung dann für die Umwandlung auszulösen. Ich persönlich ziehe die .to_double Syntax, es sei denn, die Umwandlung, weil in diesem Fall zu bool wäre die Umwandlung von if(obj) verwendet wird, auch wenn es explicit ist, und das ist wesentlich besser lesbar als if(obj.to_bool()) meiner Meinung nach.


Lassen Sie den Konvertierungsoperator. Es führt dazu, dass Probleme der ganzen Weg. Haben Sie eine Funktion wie

to_double()

oder ähnlich, die den doppelten Wert zurückgibt und diese Funktion rufen explizit eine Doppel zu bekommen.

Für das Problem auf der Hand, gibt es dieses Problem:

obj >= 10

Betrachten Sie diesen Ausdruck. Der eingebaute Operator entspricht das erste Argument von einer benutzerdefinierten Umwandlungsfolge für Ihre Art lange die Konvertierung Operator Doppel (). Aber Ihre Funktion entspricht dem zweiten Argument durch eine Standard-Konvertierungssequenz von int in long double (integral zu Gleitkomma-Umwandlung). Es ist immer zweideutig, wenn es Konvertierungen für zwei Argumente, aber nicht mindestens ein Argument, das besser umgesetzt werden kann, während die übrigen Argumente für schlechter einen Anruf nicht umgewandelt werden. In Ihrem Fall entspricht das builtin eines das zweite Argument besser, aber die ersten schlechter, aber Ihre Funktion entspricht das erste Argument besser, aber die zweiten schlimmer.

Es ist verwirrend, so sind hier einige Beispiele (Konvertierungen von char sind Aktionen in int genannt, die als Conversions von char auf andere etwas besser sind als int, die eine Umwandlung genannt wird):

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

Ruft die erste Version. Da alle Argumente für die erste können umgewandelt besser werden. Ebenso wird im Folgenden noch die ersten Aufruf:

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

Da kann das erste besser umgesetzt werden, und die zweite wird nicht schlechter umgewandelt. Aber die folgende ist mehrdeutig :

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

Es ist interessanter in diesem Fall. Die erste Version übernimmt das erste Argument durch eine genaue Übereinstimmung. Die zweite Version übernimmt das zweite Argument durch eine genaue Übereinstimmung. Aber beide Versionen nicht akzeptieren, ihr anderes Argument zumindest gleich gut. Die erste Version erfordert eine Umwandlung für das zweite Argument, während die zweite Version eine Förderung für ihr Argument erfordert. Also, auch wenn eine Förderung ist besser als eine Umwandlung, der Anruf an die zweite Version schlägt fehl.

Es ist sehr ähnlich zu Ihrem Fall oben. Auch wenn eine Standard-Umwandlungsfolge (Umwandlung von int / float / double zu long double) ist besser als eine benutzerdefinierte Umwandlungsfolge (von MyClass zu lange doppelte Umwandlung), wird Ihre Operator Version nicht gewählt, weil Ihr anderer Parameter (long double), um eine Umwandlung von dem Argument erfordert, die schlimmer als das, was für dieses Argument der eingebauten Operator muss, ist (perfekt).

Die Überladungsauflösung ist eine komplexe Angelegenheit in C ++, so dass man unmöglich alle subtilen Regeln darin erinnern kann. Aber den groben Plan bekommen ist durchaus möglich. Ich hoffe, es hilft Ihnen.

Andere Tipps

eine implizite Umwandlung in ein double Indem Sie effektiv sind unter Angabe ist meine Klasse entspricht einem double und aus diesem Grund sollten Sie nicht wirklich etwas dagegen, wenn die in Bediener gebaut> = für doubles verwendet wird. Wenn Sie tun Pflege, dann wirklich Ihre Klasse ist nicht ‚gleichwertig‘ zu einem double und Sie sollten erwägen, nicht bietet eine impliziten Umwandlung in double, sondern eine Bereitstellung von explizite GetAsDouble oder ConvertToDouble Memberfunktion.

Der Grund, dass Sie eine Zweideutigkeit im Moment ist, dass für einen Ausdruck t >= d wo t eine Instanz der Klasse ist und d ein doppelt so hoch ist, immer der Compiler eine Umwandlung von entweder der linken Seite zu bieten hat oder das Recht Seite so wirklich der Ausdruck ist nicht eindeutig. Entweder t die operator double aufgerufen und die eingebaute Operator> = für doubles verwendet wird, oder d muss einen long double und Ihr Mitglied Betreiber gefördert werden> = verwendet wird.

Bearbeiten, haben Sie Ihre Frage aktualisiert lassen vermuten, dass Ihre Umstellung auf lange doppelt so hoch ist und Ihr Vergleich ist gegen einen int. In diesem Fall sollte der letzte Absatz lesen:

Der Grund, dass Sie eine Zweideutigkeit im Moment ist, dass für einen Ausdruck t >= d wo t eine Instanz der Klasse ist und d ein int ist, immer der Compiler eine Umwandlung von entweder der linken Seite zu bieten hat oder das Recht Seite so wirklich der Ausdruck ist nicht eindeutig. Entweder t die operator long double aufgerufen und die eingebaute Operator> = für long double und int verwendet wird, oder d muss einen long double und Ihr Mitglied Betreiber gefördert werden> = verwendet wird.

Ich nehme an, Sie gegen eine wörtliche int vergleichen, und keinen long double:

MyClass o;

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

Wenn das der Fall beide Alternativen sind so gut / komplex.

Mit Ihrem operator long double():

  1. MyClass::operator long double()
  2. Einbau-operator>=(long double, int)

Mit Ihrem MyClass::operator>=(long double):

  1. Einbau-Umwandlung int long double
  2. MyClass::operator>=(long double)

Sie haben long double in der Erklärung bekommen. Versuchen Sie, es double.

Ihre Nutzung des Bedieners mit benutzerdefinierten Gießen kombiniert Überlastung Benutzer Ihrer Klasse kann sehr verwirrend sein. Fragen Sie sich, würden Nutzer dieser Klasse erwarten es sich in ein Doppel zu konvertieren oder vergleichbar mit einem Doppel? Wäre das nicht ein .greaterThan (double) mit Funktion das gleiche Ziel erreichen, aber ohne den Anwender zu überraschen?

Ich denke, man könnte immer explizit wirft Ihr Objekt vor dem Vergleich, verdoppeln, um die Mehrdeutigkeit zu vermeiden. Aber wenn ich Sie wäre, würde ich den Ansatz oben überdenken und auf das Schreiben von Code konzentrieren, die intuitiv ist und verhält sich in einer Weise überraschend, statt Phantasie Art Guss und Betreiber Überlastung.

(inspiriert durch die wunderbaren rant rel="nofollow über Betreiber Überlastung )

  • Die eingebauten Operator> = (long double, int).

Sieht aus wie Sie definiert haben:

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

Und Sie fehlen:

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

So ist der Compiler nicht, welcher Weg zu konvertieren entscheiden kann. (Es ist nicht eindeutig.)

Vielleicht eine Templat-Funktion (oder Methode) wäre hilfreich?

Achten Sie auf Situationen, in denen a> = b ruft verschiedene Methoden als b> = a .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top