Jak porównać dwie standardowe sekwencje konwersji, użyj rangi zawartych konwersji
#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 ambiguous
diagnostykę.
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 #3
najlepiej 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 conversion
jest 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 conversion
z S2
jest właściwe podciąg Array-to-pointer conversion
z 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
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 conversion
i qualification conversion
odpowiednio.
Zgodnie z zasadą:
sekwencja konwersji tożsamości jest uważana za podsekwencję dowolnej sekwencji konwersji nieidentyfikującej
W związku z tym Qualification conversion
uważa się, że ma gorszą rangę niż ranga identity conversion
. Więc void f(int*)
wygrał konkurs.
Próbujesz zastosować over.ics.rank-3.2.1 do tych zestawów przeciążeniowych, ale zasada ta nie ma zastosowania do albo f
lub 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
, T1
jest int *
i T2
to int const *
, i T1
może być przekształcony T2
przez 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 .
f
Jednak 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.