Jak porównać dwie standardowe sekwencje konwersji, użyj rangi zawartych konwersji

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
}

Weź pod uwagę powyższy kod, dla którego wybrano # 3f(ptr) , jednak g(arr)daje ambiguousdiagnostykę.

Reguła wyboru najlepszej funkcji jest zdefiniowana jako:

Standardowa sekwencja konwersji S1 jest lepszą sekwencją konwersji niż standardowa sekwencja konwersji S2, jeśli

  • S1 jest właściwą podsekwencją S2 (porównując sekwencje konwersji w formie kanonicznej zdefiniowanej przez [over.ics.scs], z wyłączeniem wszelkich transformacji L-wartości; sekwencja konwersji tożsamości jest uważana za podsekwencję dowolnej sekwencji konwersji nieidentyfikującej ) lub jeśli nie to

Spójrz więc na over.ics.scs # 3

Są one używane do rangowania standardowych sekwencji konwersji. Rangę sekwencji konwersji określa się, biorąc pod uwagę rangę każdej konwersji w sekwencji i rangę dowolnego wiązania odniesienia.

Zgodnie z moim rozumieniem powyższej zasady rozumiem, dlaczego #3najlepiej jest przeciążać f(ptr), czyli:

Biorąc pod uwagę S1 jako (arr => int *):

Array-to-pointer conversion -> (identity conversion)  
^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^                   
     int[2] => int*             int* => int* 

podczas gdy dane S2 jako (ptr => int const *)

Array-to-pointer conversion -> Qualification conversions ->  identity conversion   
^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^ 
     int[2] => int*               int* => int const*           int const* => int const* 

Ponieważ identity conversionjest to właściwy podciąg Qualification conversions, stąd S1 jest lepsze niż S2. Tak więc numer 3 jest wybierany na podstawie rozdzielczości przeciążenia dla f(ptr).

Kiedy używam podobnego procesu, aby określić, który z nich jest najlepszy g(arr), napotykam problem.

Ponownie, biorąc pod uwagę S1 jako (arr => int *)

Array-to-pointer conversion -> identity conversion  
^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^ 
      int[2] => int*              int* => int*

podczas gdy dane S2 jako (arr => int (& arr) [2])

Gdy parametr typu referencyjnego wiąże się bezpośrednio z wyrażeniem argumentu, niejawna sekwencja konwersji jest konwersją tożsamości, chyba że wyrażenie argumentu ma typ, który jest klasą pochodną typu parametru, w którym to przypadku niejawna sekwencja konwersji jest pochodną konwersja do bazy

identity conversion
^^^^^^^^^^^^^^^^^^^
  bind to reference   

Tutaj identity conversionz S2jest właściwe podciąg Array-to-pointer conversionz S1, stąd powinno być lepiej niż S1, dlaczego kompilator skarżył g(arr)jest niejednoznaczna wezwanie?

Czy mam jakieś błędne informacje o tym, jak uszeregować standardowe sekwencje konwersji? Jak porównać dwa standardowe ICS (ranking zawartej konwersji)?

Odpowiedzi

2 jackX Dec 11 2020 at 16:02

Kluczowa kwestia jest tutaj:

S1 jest właściwą podsekwencją S2 (porównując sekwencje konwersji w formie kanonicznej zdefiniowanej przez [over.ics.scs], z wyłączeniem wszelkich transformacji L-wartości ; sekwencja konwersji tożsamości jest uważana za podsekwencję dowolnej sekwencji konwersji nieidentyfikującej) lub jeśli nie to

Oznacza to, że do wywołania funkcji g(arr), wszystko Array do wskaźnika konwersji nie są używane do określenia rangę. Innymi słowy, z typu int[2]na typ int*istnieje tylko konwersja tożsamości, która służy do określenia pozycji. Stąd S1 of void g(int*);i S2 of void g(int (&arr)[2]);są nierozróżnialne ICS, stąd kompilator podaje niejednoznaczny błąd.

W przeciwieństwie do tego, konwersje dla void f(int*);i void f(int const*);wykorzystywane są do porównania rangę identity conversioni qualification conversionodpowiednio.

Zgodnie z zasadą:

sekwencja konwersji tożsamości jest uważana za podsekwencję dowolnej sekwencji konwersji nieidentyfikującej

W związku z tym Qualification conversionuważa się, że ma gorszą rangę niż ranga identity conversion. Więc void f(int*)wygrał konkurs.

cigien Dec 11 2020 at 16:14

Próbujesz zastosować over.ics.rank-3.2.1 do tych zestawów przeciążeniowych, ale zasada ta nie ma zastosowania do albo flub g.


Biorąc pod uwagę wywołanie f(arr);, podczas wykonywania rozpoznawania przeciążenia dla f, oba przeciążenia wymagają standardowej sekwencji konwersji składającej się z konwersji tablicy na wskaźnik i oba mają tę samą rangę, czyli dokładne dopasowanie . W tym przypadku rozstrzygający remis to over.match.best # over.ics.rank-3.2.5 :

Standardowa sekwencja konwersji S1 jest lepszą sekwencją konwersji niż standardowa sekwencja konwersji S2, jeśli

...

S1 i S2 różnią się jedynie konwersją kwalifikacji ([równa konw.]) I dają podobne typy odpowiednio T1 i T2, gdzie T1 można przekształcić w T2 przez konwersję kwalifikacji.

Istnieje przykład następujący po tej regule, który pokazuje, jak działa ta reguła.

Dla zestawu przeciążeniem f, T1jest int *i T2to int const *, i T1może być przekształcony T2przez kwalifikacyjnego konwersji.


W przypadku wywołania g(arr);, podczas wykonywania rozpoznawania przeciążenia, przeciążenie g(int (&)[2])jest klasyfikowane jako dopasowanie ścisłe , ponieważ wymagana standardowa sekwencja konwersji to Nie jest wymagana konwersja .

Jednak przeciążenie g(int*)jest również klasyfikowane jako dopasowanie ścisłe , ponieważ wymagana standardowa sekwencja konwersji to konwersja typu Array-to-Pointer .

fJednak w przeciwieństwie do for , w [over.ics.rank] nie ma reguły, która rozróżnia standardowe sekwencje konwersji dla g, a wywołanie kończy się niepowodzeniem.