5

Visual C++ 2012. 코드. 나는 그것이 컴파일되어야한다고 생각한다; 컴파일러는 정중하게 동의하지 않습니다. 아래로 범위를 좁혔습니다.VC++ 2012에서 예기치 않게 모호한 오버로드 해결

struct B { }; 

void foo(B* b, signed int si) { } // Overload 1 
void foo(B const* b, unsigned int ui) { } // Overload 2 

int main() 
{ 
    B b; 
    unsigned int ui; 
    foo(&b, ui); 
} 

그래서 과부하 해결을위한 후보가 두 가지 있습니다. 첫 번째 오버로드의 경우 첫 번째 인수는 정확히 일치하고 두 번째 인수는 정수 변환 (부호가없는 부호가있는)이 필요합니다. 두 번째 오버로드의 경우 두 번째 인수가 정확히 일치하고 첫 번째 인수는 cv 조정이 필요합니다 (&b은 비 const에 대한 포인터이기 때문에).

이제 완전히 모호한 것으로 보입니다. 오버로드 1의 경우 첫 번째 인수는 과부하 해결에 대한 표준 섹션에서 정의한 "완전 일치"이지만 두 번째 인수는 "변환"입니다. 오버로드 2의 경우 두 인수가 모두 "완전 일치"입니다 (자격 변환은 동일성 순위와 동일 함). 따라서 (내 명백하게 불완전한 추론이 진행됩니다.) 과부하 2는 모호성없이 선택되어야합니다. 그리고 아직 :

a.cpp(12): error C2666: 'foo' : 2 overloads have similar conversions 
    a.cpp(6): could be 'void foo(const B *,unsigned int)' 
    a.cpp(5): or  'void foo(B *,int)' 
    while trying to match the argument list '(B *, unsigned int)' 
    note: qualification adjustment (const/volatile) may be causing the ambiguity 

GCC는 기본 언어와 C++ 11 (감사합니다, IDEOne!) 모두에서 코드와 잘 어울립니다. 그래서 저는 MSVC의 버그에 대해이 글을 쓰는 경향이 있습니다. 그러나 (a) 여러분은 자신의 버그가 컴파일러 버그라고 생각하는 사람들에 대해 무엇을 말하는지 알 것입니다. (b) 이것은 꽤 명백한 버그 일 것입니다. , 적합성 테스트 중에 적색 플래그를 보냈을 것입니다.

이 메시지는 비 호환 MSVC입니까, 아니면 비 호환 GCC입니까? (또는 둘 다?) 과부하 해결 소리에 관한 나의 추론은 무엇입니까?

+1

어떤 컴파일러가 정확한지 모르겠지만 인간으로서 나는 두 가지 유형의 변환의 우선 순위에 따라 명확성을 제거하지 않고 어떤 오버로드가 사용되는지 알고 싶어합니다 .-) – Cameron

+0

@Cameron Oh, I 동의하다. 실제 유스 케이스는 훨씬 더 의미가 있으며, 실제로 * 보이는 * 모호하지 않습니다. – Sneftel

답변

7

MSVC가 정확합니다.

GCC 4.9.0는 말한다 :

경고 : ISO C++에서이 첫 번째의 최악의 변환이 초 최악의 변환보다 더 나은에도 불구하고, 모호한 것을 말한다 :

[기본적으로 활성화]

clang 3.4.1은 두 기능이 모호하다는 데 동의합니다. 모두 완전 일치 순위가 B* => B*B* => B const* 있지만

는, 전자는 여전히 over.ics.rank/3 당 더 나은 변환 순서입니다; 이것은 다음을 보장하기 위해 (예를 들어 PER)이다

int f(const int *); 
int f(int *); 
int i; 
int j = f(&i); // calls f(int*) 

over.ics.rank/3에서 :

표준 변환 시퀀스 S1 표준 변환 시퀀스 S2보다 우수한 전환 서열의 경우 [이다 .. ]
- S1과 S2는 자격 변환에서만 차이가 있으며 유사한 유형 T1 및 T2 (4.4)를 각각 산출하며 유형 T1의 CV 자격 서명은 유형 T2의 CV 자격 서명의 적절한 하위 집합입니다. [...]

물론, unsigned int => unsigned intunsigned int => signed int보다 좋습니다. 따라서 두 가지 오버로드 중 하나는 첫 번째 인수에서 더 나은 암시 적 변환 시퀀스를 사용하고 다른 하나는 두 번째 인수에서 더 나은 암시 적 변환 시퀀스를 사용합니다. 따라서 over.match.best/1에 따라 구분할 수 없습니다.

+0

감사합니다. 내 추론의 결함은 뭐니? 오버로드를 비교할 때 컴파일러가 'B *'를'B const * '보다 더 선호해서는 안됩니다. 오버로드 1에 대한 해당 변환보다 나쁜 오버로드 2에 대한 변환이 없다는 것을 표준을 읽은 것으로 보입니다. – Sneftel

+0

@Sneftel 아, 그렇습니다. 정확한 문구를 추가하겠습니다. – ecatmur

+0

예치, 방금 발견했습니다. 내가 너무 일찍 책을 그만 둔 것처럼 보입니다. 주위를 파고 주셔서 감사합니다. – Sneftel

관련 문제