Gegeben das folgende Programm:
%Vor% Er kompiliert in Visual Studio 11, aber nicht in clang oder gcc. Es hat Probleme, weil es implizit von einem GenericType
in ein int
in ein char
umwandeln möchte, aber es könnte auch ein string
zurückgeben und somit gibt es eine Mehrdeutigkeit ( operator=(char)
und operator=(string)
stimmen beide überein GenericType
).
Der Kopierkonstruktor ist jedoch in Ordnung.
Meine Frage ist: Wie kann ich diese Mehrdeutigkeit auflösen, ohne den Inhalt von main zu ändern? Was muss ich tun, um GenericType
zu ändern, um mit dieser Situation umzugehen?
Ich glaube, dass gcc und clang korrekt sind.
Es gibt zwei operator=
Überladungen im Spiel:
Diese beiden operator=
Überladungen erfordern eine benutzerdefinierte Konvertierung von Ihrem Argument vom Typ GenericType
. (1) erfordert die Verwendung der Umwandlung in string
. (2) erfordert die Verwendung der Konvertierung in int
, gefolgt von einer Standardkonvertierung in char
.
Wichtig ist, dass beide Überladungen eine benutzerdefinierte Konvertierung erfordern. Um festzustellen, ob eine dieser Konvertierungen besser ist als die andere, können wir uns die Regeln für die Überladungsauflösung ansehen, insbesondere die folgende Regel aus C ++ 11 §13.3.3.2 / 3 (zur besseren Übersichtlichkeit umformatiert):
Die benutzerdefinierte Konvertierungssequenz
U1
ist eine bessere Konvertierungssequenz als eine andere benutzerdefinierte KonvertierungssequenzU2
if
Sie enthalten dieselbe benutzerdefinierte Konvertierungsfunktion oder Konstruktor- oder Aggregat-Initialisierung und
Die zweite Standardkonvertierungssequenz von
U1
ist besser als die zweite Standardkonvertierungssequenz vonU2
.
Beachten Sie, dass ein und die beiden Teile der Regel verbindet, sodass beide Teile erfüllt sein müssen. Der erste Teil der Regel ist nicht erfüllt: Die beiden benutzerdefinierten Konvertierungssequenzen verwenden verschiedene benutzerdefinierte Konvertierungsfunktionen.
Daher ist keine Konvertierung besser und der Aufruf ist nicht eindeutig.
[Ich habe keinen guten Vorschlag, wie ich das Problem beheben kann, ohne die Definition von main()
zu ändern. Implizite Conversions sind normalerweise keine gute Idee. Sie sind manchmal sehr nützlich, aber häufiger verursachen sie Überlastungs-Ambiguitäten oder ein anderes seltsames Überlastungsverhalten.]
Es gab einen GCC-Fehlerbericht, in dem dieses Problem beschrieben und wie geplant behoben wurde: Compiler falsch diagnostiziert mehrdeutige Bedienerüberlastung.
Ich glaube, dass GCC falsch ist. In dem Buch "Die Programmiersprache C ++" von Bjarne Stroustrup gibt es ein ganzes Kapitel, das der Überlastung von Operatoren gewidmet ist. In Abschnitt 11.4.1 heißt es im ersten Absatz:
"Eine Zuweisung eines Wertes vom Typ V an ein Objekt der Klasse X ist zulässig, wenn es einen Zuweisungsoperator X :: operator = (Z) gibt, so dass V Z ist oder eine eindeutige Umwandlung von V nach Z erfolgt. Die Initialisierung wird äquivalent behandelt. "
In Ihrem Beispiel akzeptiert GCC "string s = GenericType ();" lehnt jedoch "s = GenericType ();" ab, so dass die Zuweisung offensichtlich nicht wie bei der Initialisierung behandelt wird. Das war mein erster Hinweis, dass in GCC etwas nicht stimmt.
GCC meldet 3 Kandidaten für die Konvertierung von GenericType in string in der Zuweisung, alles in basic_string.h. Die eine ist die korrekte Umwandlung, die eine, die sie meldet, ist nicht gültig, und die dritte verursacht die Mehrdeutigkeit. Dies ist die Überladung des Operators in basic_string.h, die die Mehrdeutigkeit verursacht:
%Vor% Dies ist keine gültige Konvertierung , weil sie einen Operanden akzeptiert, der nicht mit dem Objekttyp übereinstimmt, der an ihn übergeben wird. An keiner Stelle wird als Zuordnung zu einem Char versucht, daher sollte diese Konversion gar kein Kandidat sein, viel weniger eine, die Mehrdeutigkeit verursacht. GCC scheint den Schablonentyp mit dem Operandentyp in seinem Member zu verwechseln.
BEARBEITEN: Mir war nicht bewusst, dass das Zuweisen einer Ganzzahl zu einer Zeichenkette tatsächlich zulässig ist, da eine Ganzzahl in ein Zeichen umgewandelt werden kann, das einer Zeichenkette zugewiesen werden kann (obwohl eine Zeichenkette nicht mit a initialisiert werden kann) verkohlen!). GenericType definiert eine Umwandlung in ein int und macht dieses Mitglied somit zu einem gültigen Kandidaten. Ich behaupte jedoch immer noch, dass dies keine gültige Konvertierung ist, da die Verwendung dieser Konvertierung zu zwei benutzerdefinierten impliziten Konvertierungen für die Zuweisung führt, zuerst von GenericType nach int und dann von int nach string. Wie in demselben Buch 11.4.1 erwähnt, ist "nur eine Stufe der benutzerdefinierten impliziten Konvertierung zulässig."
Meine Frage ist: Wie kann ich diese Mehrdeutigkeit auflösen, ohne den Inhalt von main zu ändern?
Erstellen Sie Ihre eigene Klasse mit dem Namen string
, die kein mehrdeutiges operator=
hat und dann nicht using
das std
eins.
Offensichtlich ist das keine sehr gute Lösung, aber es funktioniert und main
muss sich nicht ändern.
Ich glaube nicht, dass Sie das gewünschte Verhalten auf andere Weise bekommen können.
Tags und Links string c++ overload-resolution implicit-conversion conversion-operator