14

Der folgende C++ Programm ohne Warnungen in allen Compilern kompiliert Ich habe versucht (gcc 4.6.3, llvm 3.0, icc 13.1.1, SolarisStudio 12.1/12.3):Verschiedene Guss Betreiber von verschiedenen Compilern verwendet

struct CClass 
{ 
    template<class T> 
    operator T() const { return 1; } 

    operator int() const { return 2; } 
}; 

int main(void) 
{ 
    CClass x; 
    return static_cast<char>(x); 
} 

Alle SolarisStudio-Compiler geben jedoch 2 zurück, SolarisStudio (beide Versionen) gibt 1 zurück, was ich als das logischste Ergebnis erachte.

Mit return x.operator char(); Ergebnisse in allen Compilern 1.

Offensichtlich zurückkehren, dies seit herauszufinden, habe ich die letztere Notation. Ich würde jedoch gerne wissen, welcher der Compiler korrekt ist und warum. (Man würde denken, dass die Mehrheit Regeln, aber diese nicht erklärt noch nicht die warum.)

Diese Frage zu den SO Fragen zu sein scheint here, here und here, aber diese „nur“ geben Lösungen Probleme, keine Erklärungen (die ich sowieso auf mein spezielles Problem anwenden konnte).

Beachten Sie, dass das Hinzufügen eines zusätzlichen überladenen Casting-Operators, z. B. operator float() const { return 3; }, dazu führt, dass sich alle Compiler außer SolarisStudio über Unklarheiten beschweren.

+0

Nur getestet in meinem Compiler, G ++ 4.8.0, und es gibt 1. – rodrigo

+1

G ++ 4.7.2 gibt auch 1. Und mit 'operator float()' gibt es keine Beschwerde über Zweideutigkeiten. – hvd

+2

g ++ gibt eine ab 4.7 zurück http://gcc.godbolt.org/ – Riga

Antwort

9

Die erste Überladung (Vorlage) sollte ausgewählt werden.

Paragraph 13.3.3/1 der C++ 11-Standard spezifiziert:

[...] eine brauchbare Funktion F1 ist definiert als eine bessere Funktion als eine andere brauchbare Funktion seine F2 wenn für alle Argumente i, ist ICSi(F1) keine schlechte Umwandlungsfolge als ICSi(F2) und

dann - für einig Argument j, ICSj(F1) ist eine bessere Conversion-Sequenz als.210, oder, falls nicht,

- der Kontext eine Initialisierung durch benutzerdefinierte Konvertierung ist (siehe 8.5, 13.3.1.5 und 13.3.1.6) und die Standardkonvertierungssequenz von dem Rückgabetyp F1 an den Zieltyp (dh die Art der Einheit initialisiert wird) a von der Rückgabetyp von F2 zum Zieltyp bessere Umwandlungsfolge als die Standard-Umwandlungsfolge ist.[Beispiel:

struct A { 
    A(); 
    operator int(); 
    operator double(); 
} a; 
int i = a; // a.operator int() followed by no conversion 
      // is better than a.operator double() followed by 
      // a conversion to int 
float x = a; // ambiguous: both possibilities require conversions, 
      // and neither is better than the other 

- Ende Beispiel] oder wenn nicht, dass,

- F1 ist eine nicht-Template-Funktion und F2 ist eine Spezialisierung Template-Funktion oder, wenn nicht, dass

[...]

Wie Sie sehen, wird die Tatsache, dass der erste Konvertierungsoperator eine Vorlage ist, nur relevant, wenn die Standardkonvertierungssequenz von ihrem Rückgabetyp (char in diesem Fall) zum Zieltyp (char in diesem Fall) nicht ist besser als die Standard-Konvertierungssequenz vom Rückgabetyp der Nicht-Template-Überladung (in diesem Fall int) zum Zieltyp (in diesem Fall char).

jedoch eine Standard-Konvertierung von char zu char ist ein Exact Match, während eine Standard-Konvertierung von int zu char nicht ist. Daher gilt der dritte Punkt des § 13.3.3/1 nicht und der zweite Punkt.

Dies bedeutet, dass die erste (Vorlage) Überladung sollte ausgewählt werden.

+0

Nicht wirklich. Es sagt, dass eine Schablone ** Spezialisierung ** darüber ausgewählt wird. Aber in dem Fall gibt es keine Spezialisierung. Der Compiler wird nicht einmal mit dem Erstellen einer Vorlage beginnen, weil er bereits eine passende Nicht-Template-Umwandlung gefunden hat, die er verwenden kann. Vorlagen werden nur erstellt, wenn sie explizit aufgerufen werden oder es keine andere Überladung gibt. Es gibt keinen Grund dafür, dass der Compiler bei einer passenden Vorlage "rät" –

+0

@YochaiTimmer: Nein, das stimmt einfach nicht. Es wird die Vorlage nicht instanziieren, aber es wird eine Vorlagendargumentableitung durchführen und sehen, ob die Vorlage ein praktikabler Kandidat für die Überladungsauflösung ist. Wenn sich herausstellt, dass dies der * beste * durchführbare Kandidat ist, wird er ihn auswählen und instanziieren –

5

Die erste ist eine exakte Übereinstimmung, die zweite erfordert eine Konvertierung. Exakte Treffer haben Vorrang vor Conversions.

Diese anderen Fragen, die Sie verlinkt haben, haben meistens nichts mit Ihren zu tun.

Einige Ratschläge: Verwenden Sie keine Template-Konvertierungsoperatoren. Nennen Sie es stattdessen convert_to.

+1

+1 für die Warnung vor Vorlagenkonvertierungsoperatoren. Vielleicht könnten Sie eine Erklärung hinzufügen, warum das gefährlich ist. – Walter