Momentan versuche ich den Absatz zu verstehen [over.match.oper] / 7 in der C ++ - Standard, aber der folgende Fall, bei dem GCC und Clang verschiedene Ergebnisse produzieren:
%Vor%Hier sind Zitate des entsprechenden Absatzes aus Versionen von Standards:
C ++ 1z (N4659) 16.3.1.2 [over.match.oper] Absatz 7
(im Wesentlichen dasselbe mit C ++ 14 (N4140) 13.3.1.2 [over.match.oper] Absatz 7 ):
Wenn ein integrierter Kandidat durch Überladungsauflösung ausgewählt wird, werden die Operanden des Klassentyps in die Typen der entsprechenden Parameter der ausgewählten Operationsfunktion konvertiert, mit Ausnahme der zweiten Standardkonvertierungssequenz einer benutzerdefinierten Konvertierungssequenz ( 16.3.3.1.2) wird nicht angewendet. Dann wird der Operator als der entsprechende eingebaute Operator behandelt und gemäß Klausel 8 interpretiert. [Beispiel:
%Vor%- Ende Beispiel]
C ++ 03 13.3.1.2 [over.match.oper] Absatz 7
(im Wesentlichen dasselbe mit C ++ 11 (N3291) 13.3.1.2 [over.match.oper] Absatz 7 ):
Wenn ein eingebauter Kandidat durch Überladungsauflösung ausgewählt wird, werden die Operanden in die Typen der entsprechenden Parameter der ausgewählten Operationsfunktion umgewandelt. Dann wird der Operator als der entsprechende eingebaute Operator behandelt und gemäß Klausel 5 interpretiert.
Die Änderung in C ++ 14 wurde von CWG 1687 eingeführt.
Ich dachte ursprünglich, dass der Top-Code in C ++ 14 schlecht aussehen sollte. Gemäß den Standards ist mein naives Verständnis des Prozesses der Überladungsauflösung des Top-Codes dies (Abschnittsnummern stammen von N4659):
Zuerst wird der Satz der Kandidatenfunktionen erzeugt. Es enthält den benutzerdefinierten Operator #1
( 16.3.1.2/(3.2) ). und ein eingebauter Operator #2
( 16.3.1.2/(3.3) , < a href="http://eel.is/c++draft/over.built#14"> 16.6 / 14 ). Als Nächstes wird die Lebensfähigkeit beider Operatoren getestet, indem implizite Konvertierungssequenzen (ICS) für jedes Argument / Parameter-Paar konstruiert werden, um den Satz lebensfähiger Funktionen zu bestimmen; Alle ICS werden erfolgreich als ICS1(#1) = int* → X
( 16.3.3.1.2 , benutzerdefiniert) erstellt Konvertierungssequenz), ICS2(#2) = Y → double → int
(benutzerdefinierte Konvertierungssequenz), ICS1(#2) = int* → int*
( 16.3.3.1/ 6 , Identitätskonvertierung, eine der Standardkonvertierungssequenzen) und ICS2(#2) = X → double → std::ptrdiff_t
(benutzerdefinierte Konvertierungssequenz), und daher sind beide Operatoren brauchbar. Dann wird die beste lebensfähige Funktion durch Vergleichen von ICS ausgewählt; Da ICS1(#2)
ist besser als ICS1(#1)
( 16.3.3.2/(2.1) ) und ICS2(#2)
ist nicht schlechter als ICS2(#1)
( 16.3.3.2/3 ), #2
ist eine bessere Funktion als #1
( 16.3.3 / 1 ). Schließlich wird der integrierte Operator #2
durch die Überladungsauflösung ausgewählt ( 16.3.3 / 2 ).
Wenn ein integrierter Operator ausgewählt wird, wird die oben genannte Regel ( 16.3.1.2/7 ) gilt: Nach dem Anwenden von ICS auf die Argumente wird die Behandlung des Operatorausdrucks in Abschnitt 8 [Ausdruck] übertragen. Hier unterscheidet sich die Anwendung von ICS in C ++ 11 und C ++ 14. In C ++ 11 werden ICS vollständig angewendet, also wird (int*) y + (std::ptrdiff_t) (double) n
berücksichtigt, und es ist in Ordnung. Während in C ++ 14 die zweiten Standard-Konvertierungssequenzen in benutzerdefinierten Konvertierungssequenzen nicht angewendet werden, wird (int*) y + (double) n
berücksichtigt. Dies führt zu einer Verletzung der semantischen Regel ( 8.7 / 1 ), dh der Ausdruck ist schlecht gebildet und Implementierung ist erforderlich, um Diagnosemeldungen auszugeben.
Clang wählt #2
und ruft es ohne Diagnosemeldungen bei Verletzung 8.7 / 1 auf. Meine Vermutung ist, dass Clang ICSs vollständig auf die Argumente anwendet, bevor es den Aufruf an die eingebauten Regeln (8.7 / 1) überträgt, und dies ist ein Fehler.
GCC wählt #1
ohne Diagnose. Der Microsoft C / C ++ - Compiler in Visual Studio 2017 scheint sich gleich zu verhalten. Auch dieses Verhalten scheint mir vernünftig zu sein ( Bearbeiten : Siehe [1]).
Ich denke, GCC hält #2
für nicht lebensfähig und dann ist nur die lebensfähige Funktion #1
.Aber ich konnte keine Regeln wie diese finden, dass der eingebaute Operator nicht praktikabel ist, wenn er ohne zweite Standard-Konvertierungssequenzen in benutzerdefinierten Konvertierungssequenzen schlecht gebildet wird. Wenn der Satz " mit Ausnahme der zweiten Standardkonvertierungssequenz einer benutzerdefinierten Konvertierungssequenz " von CWG 1687 eingeführt wird, scheint es tatsächlich keine weiteren Änderungen in der Definition der Lebensfähigkeit zu geben.
Frage 1 : Laut dem aktuellen Standard, welches ist die richtige Interpretation?
Frage 2 : Wenn meine naive Interpretation korrekt ist, ist das Verhalten von CWG 1687 beabsichtigt?
Fußnoten
Aktualisieren
Nach dieser Frage wurde dieses Problem für die folgenden Compiler gemeldet:
Ich stimme Ihrer Interpretation zu. Wir haben Argumente vom Typ int*
und Y
und wir haben zwei Kandidaten:
#1
benötigt zwei benutzerdefinierte Konvertierungssequenzen, #2
erfordert eine Standardkonvertierungssequenz (Exact Match, spielt dabei keine Rolle) und eine benutzerdefinierte Konvertierungssequenz. Für das erste Argument ist eine Standardkonvertierungssequenz besser als eine benutzerdefinierte Konvertierungssequenz. während für das zweite Argument die zwei Sequenzen nicht unterscheidbar sind (es gilt keines der Bedingungen ). Da die erste implizite Konvertierungssequenz in #2
besser ist als die erste implizite Konvertierungssequenz in #1
und die zweiten Konvertierungssequenzen äquivalent sind, #2
gewinnt .
Und dann post-CWG 1687, führen wir die letzte Konvertierung nicht aus double
bis ptrdiff_t
, daher sollte das Ergebnis schlecht aussehen.
Um diese Frage zu beantworten:
ist das von CWG 1687 beabsichtigte Verhalten?
Ich vermute, dass es sicher ist, da das Beispiel ist:
%Vor%
was Ihrem Beispiel sehr ähnlich ist - der einzige Unterschied ist, dass Y()
in int*
konvertiert werden kann und nicht direkt in int*
. Ich ging voran und legte gcc 81789 und llvm 34138 . Beachten Sie, dass clang CWG 1687, die Beispiele aus dieser Ausgabe und die Standardkompilierung einfach nicht implementiert.
Tags und Links c++ c++14 operator-overloading c++17