Zum Vergleichen von zwei Standardkonvertierungssequenzen wird der Rang der enthaltenen Konvertierungen verwendet

Dec 11 2020
#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 ambiguousDiagnose.

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 #3die 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 conversiones 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 conversionder S2ist eine richtige Subsequenz Array-to-pointer conversionvon S1daher 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

2 jackX Dec 11 2020 at 16:02

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 conversionund qualification conversionjeweils.

Nach der Regel:

Die Identitätskonvertierungssequenz wird als Teilsequenz einer Nichtidentitätskonvertierungssequenz betrachtet

Daher Qualification conversionwird angenommen, dass es einen schlechteren Rang hat als der von identity conversion. Also gewann void f(int*)die Konkurrenz.

cigien Dec 11 2020 at 16:14

Sie versuchen anzuwenden over.ics.rank-3.2.1 für diese Überlastung Sätze, aber diese Regel gilt nicht für entweder foder g.


Angesichts des Aufrufs erfordern beide Überladungen f(arr);beim Durchführen einer Überlastungsauflösung feine 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, T1ist , int *und T2ist int const *, und T1kann umgesetzt werden T2durch 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 fgibt es in [over.ics.rank] keine Regel, die zwischen den Standardkonvertierungssequenzen für unterscheidet g, und der Aufruf schlägt fehl.