Ambiguous string :: operator = Aufruf für Typ mit impliziter Konvertierung in int und String

8

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?

    
M2tM 24.05.2012, 18:16
quelle

3 Antworten

9

Ich glaube, dass gcc und clang korrekt sind.

Es gibt zwei operator= Überladungen im Spiel:

%Vor%

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 Konvertierungssequenz U2 if

     
  1. Sie enthalten dieselbe benutzerdefinierte Konvertierungsfunktion oder Konstruktor- oder Aggregat-Initialisierung und

  2.   
  3. Die zweite Standardkonvertierungssequenz von U1 ist besser als die zweite Standardkonvertierungssequenz von U2 .

  4.   

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.

    
James McNellis 24.05.2012, 18:29
quelle
2

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."

    
endoalir 30.05.2012 21:00
quelle
1
  

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.

    
Pubby 03.06.2012 12:42
quelle