포함 된 변환의 순위를 사용하여 두 표준 변환 시퀀스를 비교하는 방법
#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
}
위의 코드를 고려하면 # 3 은에 대해 선택 f(ptr)
되지만 진단을 g(arr)
제공합니다 ambiguous
.
최상의 기능을 선택하는 규칙은 다음과 같이 정의됩니다.
표준 변환 시퀀스 S1은 다음과 같은 경우 표준 변환 시퀀스 S2보다 더 나은 변환 시퀀스입니다.
- S1은 S2의 적절한 하위 시퀀스 (Lvalue 변환을 제외하고 [over.ics.scs]에 의해 정의 된 표준 형식의 변환 시퀀스를 비교합니다. 동일성 변환 시퀀스는 모든 비 동일성 변환 시퀀스의 하위 시퀀스로 간주 됨 ) 또는 , 그렇지 않은 경우
따라서 over.ics.scs # 3을 살펴보십시오.
표준 변환 시퀀스의 순위를 매기는 데 사용됩니다. 변환 시퀀스의 순위는 시퀀스의 각 변환 순위와 참조 바인딩 순위를 고려하여 결정됩니다.
위의 규칙에 대한 나의 이해에 따르면, #3
에 대한 최고의 과부하 인 이유를 이해할 수 있습니다 f(ptr)
.
S1이 (arr => int *)로 주어지면 :
Array-to-pointer conversion -> (identity conversion)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
S2가 (ptr => int const *)로 주어지면
Array-to-pointer conversion -> Qualification conversions -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int const* int const* => int const*
보낸 identity conversion
의 적합한 서브 시퀀스이다 Qualification conversions
따라서 S2는 S1보다 낫다. 따라서에 대한 과부하 해결에 의해 # 3 이 선택됩니다 f(ptr)
.
유사한 프로세스를 사용하여에 가장 적합한 프로세스를 결정할 g(arr)
때 문제가 발생합니다.
다시, S1이 (arr => int *)
Array-to-pointer conversion -> identity conversion
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
int[2] => int* int* => int*
S2 as (arr => int (& arr) [2])
참조 유형의 매개 변수가 인수 표현식에 직접 바인드되는 경우, 인수 표현식에 매개 변수 유형의 파생 클래스 유형이없는 경우 암시 적 변환 시퀀스는 동일성 변환입니다. to-base 변환
identity conversion
^^^^^^^^^^^^^^^^^^^
bind to reference
여기에, identity conversion
의를 S2
의 적절한 서브 순서 Array-to-pointer conversion
의는 S1
따라서 더 나은 이상이어야한다, S1
컴파일러는 불평 왜 g(arr)
애매한 호출입니까?
표준 변환 시퀀스의 순위를 매기는 방법에 대해 잘못 읽었습니까? 두 표준 ICS (포함 된 전환 순위)를 비교하는 방법은 무엇입니까?
답변
핵심은 다음과 같습니다.
S1은 S2의 적절한 하위 시퀀스 ( Lvalue 변환을 제외하고 [over.ics.scs]에서 정의한 표준 형식의 변환 시퀀스를 비교합니다 . 동일성 변환 시퀀스는 모든 비-동일성 변환 시퀀스의 하위 시퀀스로 간주 됨) 또는 , 그렇지 않은 경우
즉, 함수 호출의 g(arr)
경우 모든 배열에서 포인터로의 변환 이 순위를 결정하는 데 사용되지 않습니다. 즉, 유형에서 유형 int[2]
으로 int*
순위를 결정하는 데 사용되는 ID 변환 만 있습니다. 따라서 S1 of void g(int*);
및 S2 of void g(int (&arr)[2]);
는 구별 할 수없는 ICS이므로 컴파일러는 모호한 오류를 제공합니다.
대조적으로 순위를 비교하는 데 사용되는 void f(int*);
및에 대한 변환은 각각 및 입니다.void f(int const*);
identity conversion
qualification conversion
규칙에 따르면 :
동일성 변환 시퀀스는 모든 비 동일성 변환 시퀀스의 하위 시퀀스로 간주됩니다.
따라서 Qualification conversion
는의 순위보다 더 나쁜 순위로 간주됩니다 identity conversion
. 그래서 void f(int*)
경쟁 에서 와인을 마 셨습니다.
이러한 오버로드 세트에 over.ics.rank-3.2.1 을 적용하려고 하지만이 규칙은 f
또는에 적용되지 않습니다 g
.
호출이 주어지면에 대한 f(arr);
오버로드 해결을 수행 할 때 f
두 오버로드 모두 배열-포인터 변환 으로 구성된 표준 변환 시퀀스가 필요 하며 둘 다 동일한 순위 인 정확히 일치 를 갖습니다 . 이 경우 사용되는 타이 브레이커는 over.match.best # over.ics.rank-3.2.5입니다 .
표준 변환 시퀀스 S1은 다음과 같은 경우 표준 변환 시퀀스 S2보다 더 나은 변환 시퀀스입니다.
...
S1 및 S2는 자격 변환 ([conv.qual]) 만 다르며 각각 유사한 유형 T1 및 T2를 산출합니다. 여기서 T1은 자격 변환에 의해 T2로 변환 될 수 있습니다.
이 규칙 다음에 규칙이 작동하는 방식을 보여주는 예가 있습니다.
과부하 세트의 경우 f
, T1
is int *
및 T2
is int const *
이며 자격 변환 T1
을 T2
통해 로 변환 할 수 있습니다 .
호출의 경우 g(arr);
과부하 해결을 수행 할 때 필요한 표준 변환 시퀀스가 변환 필요 없음 이므로 오버로드 g(int (&)[2])
는 정확히 일치 로 순위가 매겨집니다 .
그러나 필요한 표준 변환 시퀀스가 Array-to-Pointer 변환 이므로 오버로드 g(int*)
는 정확히 일치 로 순위가 매겨집니다 .
f
그러나 이와 달리 [over.ics.rank]에는에 대한 표준 변환 시퀀스를 명확하게하는 규칙이 없으며 g
호출이 실패합니다.