포함 된 변환의 순위를 사용하여 두 표준 변환 시퀀스를 비교하는 방법

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
}

위의 코드를 고려하면 # 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 (포함 된 전환 순위)를 비교하는 방법은 무엇입니까?

답변

2 jackX Dec 11 2020 at 16:02

핵심은 다음과 같습니다.

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 conversionqualification conversion

규칙에 따르면 :

동일성 변환 시퀀스는 모든 비 동일성 변환 시퀀스의 하위 시퀀스로 간주됩니다.

따라서 Qualification conversion는의 순위보다 더 나쁜 순위로 간주됩니다 identity conversion. 그래서 void f(int*)경쟁 에서 와인을 마 셨습니다.

cigien Dec 11 2020 at 16:14

이러한 오버로드 세트에 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, T1is int *T2is int const *이며 자격 변환 T1T2통해 로 변환 할 수 있습니다 .


호출의 경우 g(arr);과부하 해결을 수행 할 때 필요한 표준 변환 시퀀스가 변환 필요 없음 이므로 오버로드 g(int (&)[2])정확히 일치 로 순위가 매겨집니다 .

그러나 필요한 표준 변환 시퀀스가 Array-to-Pointer 변환 이므로 오버로드 g(int*)정확히 일치 로 순위가 매겨집니다 .

f그러나 이와 달리 [over.ics.rank]에는에 대한 표준 변환 시퀀스를 명확하게하는 규칙이 없으며 g호출이 실패합니다.