Zum Vergleichen von zwei Standardkonvertierungssequenzen wird der Rang der enthaltenen Konvertierungen verwendet
#include <iostream>
void g(int*); //#1
void g(int (&arr)[2]); //#2
void f(int*); //#3
void f(int const*); //#4
int main(){
int arr[2] ={0};
f(arr); // choose #3
g(arr); //ambiguous
}
Betrachten Sie den obigen Code, # 3 ist ausgewählt f(ptr)
, g(arr)
gibt jedoch eine ambiguous
Diagnose.
Die Regel für die Auswahl der besten Funktion ist wie folgt definiert:
Die Standardkonvertierungssequenz S1 ist eine bessere Konvertierungssequenz als die Standardkonvertierungssequenz S2, wenn
- S1 ist eine geeignete Teilsequenz von S2 (Vergleichen der Konvertierungssequenzen in der durch [over.ics.scs] definierten kanonischen Form, ausgenommen jede L-Wert-Transformation; die Identitätskonvertierungssequenz wird als Teilsequenz einer Nicht-Identitätskonvertierungssequenz betrachtet ) oder , wenn nicht das
Schauen Sie sich also over.ics.scs # 3 an
Diese werden verwendet, um Standardkonvertierungssequenzen einzustufen. Der Rang einer Konversionssequenz wird bestimmt, indem der Rang jeder Konvertierung in der Sequenz und der Rang einer Referenzbindung berücksichtigt werden.
Nach meinem Verständnis der obigen Regel kann ich verstehen, warum #3
die beste Überlastung für f(ptr)
Folgendes ist:
Gegeben ist S1 als (arr => int *):
Array-to-pointer conversion -> (identity conversion)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
während S2 als gegeben ist (ptr => int const *)
Array-to-pointer conversion -> Qualification conversions -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int const* int const* => int const*
Da identity conversion
es sich um eine richtige Teilfolge von handelt Qualification conversions
, ist S1 besser als S2. Also wird # 3 durch Überlastungsauflösung für ausgewählt f(ptr)
.
Wenn ich einen ähnlichen Prozess verwende, um festzustellen, für welchen am besten geeignet ist, stoße g(arr)
ich auf ein Problem.
Wieder gegeben S1 als (arr => int *)
Array-to-pointer conversion -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
während S2 als (arr => int (& arr) [2] gegeben ist)
Wenn ein Parameter vom Referenztyp direkt an einen Argumentausdruck gebunden ist, ist die implizite Konvertierungssequenz die Identitätskonvertierung, es sei denn, der Argumentausdruck hat einen Typ, der eine abgeleitete Klasse des Parametertyps ist. In diesem Fall ist die implizite Konvertierungssequenz eine abgeleitete. to-base-Konvertierung
identity conversion
^^^^^^^^^^^^^^^^^^^
bind to reference
Hier identity conversion
der S2
ist eine richtige Subsequenz Array-to-pointer conversion
von S1
daher sollte es besser sein , als S1
, warum der Compiler beschwert g(arr)
ist ein mehrdeutiger Aufruf?
Habe ich falsche Informationen darüber, wie die Standardkonvertierungssequenzen eingestuft werden sollen? Wie vergleiche ich zwei Standard-ICS (Rang der enthaltenen Konvertierung)?
Antworten
Der entscheidende Punkt ist hier:
S1 ist eine geeignete Teilsequenz von S2 (Vergleichen der Konvertierungssequenzen in der durch [over.ics.scs] definierten kanonischen Form, ausgenommen jede L-Wert-Transformation ; die Identitätskonvertierungssequenz wird als Teilsequenz einer Nicht-Identitätskonvertierungssequenz betrachtet) oder , wenn nicht das
Das bedeutet, dass für Funktionsaufrufe nicht g(arr)
alle Array-zu-Zeiger-Konvertierungen verwendet werden, um den Rang zu bestimmen. Mit anderen Worten, von Typ int[2]
zu Typ int*
gibt es nur eine Identitätskonvertierung, mit der der Rang bestimmt wird. Daher sind S1 von void g(int*);
und S2 von void g(int (&arr)[2]);
nicht unterscheidbares ICS, daher gibt der Compiler einen mehrdeutigen Fehler aus.
Als Gegensatz dazu für die Umsätze void f(int*);
und void f(int const*);
verwendet Rang vergleichen sind identity conversion
und qualification conversion
jeweils.
Nach der Regel:
Die Identitätskonvertierungssequenz wird als Teilsequenz einer Nichtidentitätskonvertierungssequenz betrachtet
Daher Qualification conversion
wird angenommen, dass es einen schlechteren Rang hat als der von identity conversion
. Also gewann void f(int*)
die Konkurrenz.
Sie versuchen anzuwenden over.ics.rank-3.2.1 für diese Überlastung Sätze, aber diese Regel gilt nicht für entweder f
oder g
.
Angesichts des Aufrufs erfordern beide Überladungen f(arr);
beim Durchführen einer Überlastungsauflösung f
eine Standardkonvertierungssequenz, die aus einer Array-zu-Zeiger- Konvertierung besteht, und beide haben denselben Rang, nämlich Exakte Übereinstimmung . Der in diesem Fall verwendete Kabelbinder ist over.match.best # over.ics.rank-3.2.5 :
Die Standardkonvertierungssequenz S1 ist eine bessere Konvertierungssequenz als die Standardkonvertierungssequenz S2, wenn
...
S1 und S2 unterscheiden sich nur in ihrer Qualifikationsumwandlung ([conv.qual]) und ergeben ähnliche Typen T1 bzw. T2, wobei T1 durch eine Qualifikationsumwandlung in T2 umgewandelt werden kann.
Es gibt ein Beispiel, das dieser Regel folgt und zeigt, wie die Regel funktioniert.
Für den Überlastsatz f
, T1
ist , int *
und T2
ist int const *
, und T1
kann umgesetzt werden T2
durch eine Qualifizierungsumwandlung.
Im Fall des Aufrufs g(arr);
wird bei der Durchführung der Überlastungsauflösung die Überlast g(int (&)[2])
als exakte Übereinstimmung eingestuft , da als Standardkonvertierungssequenz " Keine Konvertierung erforderlich" erforderlich ist .
Die Überladung g(int*)
wird jedoch auch als exakte Übereinstimmung eingestuft , da die erforderliche Standardkonvertierungssequenz eine Array-zu-Zeiger- Konvertierung ist.
Im Gegensatz zu beispielsweise f
gibt es in [over.ics.rank] keine Regel, die zwischen den Standardkonvertierungssequenzen für unterscheidet g
, und der Aufruf schlägt fehl.