2012-08-09 3 views
1

다음과 같은 오버로드 된 함수 호출이 모호한 이유는 무엇입니까 ??이러한 오버로드 된 함수 호출이 모호한 이유는 무엇입니까?

call of overloaded 'test(long int)' is ambiguous,candidates are: void test(A)| void test(B)|

코드 : 컴파일 오류로 오버로드 확인이 두 동등하게 실행 가능한 기능 (모두 사용자 정의 변환을) 선택하기 때문에

class A 
{ 
    public: 
     A(int){} 
     A(){} 
}; 

class B: public A 
{ 
    public: 
     B(long){} 
     B(){} 
}; 

void test(A a) 
{ 
} 

void test(B b) 
{ 
} 

void main() 
{ 
    test(0L); 
    return; 
} 

답변

5

당신은 오류가 발생했습니다. 기능 과부하 해결은 매우 복잡한 주제입니다. 과부하 해결에 대한 자세한 내용은 다음을 참조하십시오. 이 recent lecture Stephan T. Lavavej 저. 일반적으로 단일 인수 생성자를 explicit으로 만든 다음 명시 적 생성자 인수로 함수를 호출하는 것이 가장 좋습니다.

test(0L)은 과부하가 없으므로 test(long)이므로 과부하와 정확히 일치하지 않습니다. 제공 한 두 가지 오버로드에는 인수에 대한 사용자 정의 변환이 있지만 컴파일러는이 두 가지 오버로드가 동일하게 실행 가능하다고 간주합니다. A 오버로드는 표준 변환 (int에서 long으로)을 수행 한 다음 사용자 정의 변환 (int에서 A로)을 수행하고 B은 사용자 정의 변환 (B에서 long)을 오버로드해야합니다. 그러나 모두 암시 적 사용자 정의 변환 시퀀스입니다.

이러한 등급은 어떤 방식으로 결정됩니까? 기준은 예를 들어 속보 타이 암시 적 변환 시퀀스 [over.ics.rank]

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if S1 is a proper subsequence of S2

이러한 유형 랭킹 13.3.3.2 말한다 A가 B의 파생 클래스 일 경우 적용 (또는 그 반대). 그러나 여기에서는 변환 시퀀스가 ​​다른 시퀀스의 하위 시퀀스가 ​​아닙니다. 따라서 이들은 동등하게 실행 가능하며 컴파일러는 호출을 해결할 수 없습니다.

class A 
{ 
public: 
    explicit A(int){} 
    A(){} 
}; 

class B: public A 
{ 
public: 
    explicit B(long){} 
    B(){} 
}; 

void test(A a) 
{} 

void test(B b) 
{} 

int main() 
{ 
    test(A(0L)); // call first overload 
    test(B(0L)); // call second overload 
    return 0; 
} 

참고 :이 int main()하지 void main()입니다.

+0

+1 이것은 설명을 약간 확장 할 수 있지만 공식적으로는 가장 정확한 대답입니다. – Xeo

+0

@rhalbersma :하지만 test (0L)가 (B b)보다 정확하게 일치한다고 생각합니까? 왜 모호한가요? –

+0

'0L'은'long'이므로 두 번째 문단은 "거기에'test (long)'가 없다고 말해야합니다." – Xeo

0

이 시도 :

class A 
{ 
    public: 
    explicit A(int){} 
    A(){} 
}; 

키워드 명시 적 암시 적 변환을하고있는 컴파일러를 중지합니다.

1

함수 오버로드는 정확한 인수 유형 또는 암시 적 변환을 고려합니다. 예제에서 A (0L)와 B (0L)의 두 가지 대안은 암시 적 생성자 호출이 필요하기 때문에 오버로드 관점에서 동일합니다.

1

long 유형의 매개 변수로 test를 호출하고 있습니다.

테스트하지 않습니다 (길다).

컴파일러는 테스트 (A)와 테스트 (B) 중 하나를 선택해야합니다. 따라서 B.에게>

를 - 그것은 롱 전환 서열을 갖는다> A.

통화 시험 (B) -> INT -

는 롱 전환 서열을 갖는 시험 (A)를 호출하려면 표준의 순위 규칙에서 하나가 다른 것보다 더 잘 평가되면 하나를 선택하거나 모호한 것으로 실패 할 것입니다.

이 특정 경우에 두 변환 시퀀스는 동일하게 순위가 매겨집니다.

이 섹션에서 변환 서열의 순위를 계산하는 방법에 대한 표준 규칙의 긴 목록이있다 13.3.3 가장 실행 가능한 기능 "

컴파일러는 사용자 유형에 하나의 암시 적 변환을 수행 할 수있다
+0

그리고 규칙은 어디에 있습니까 ?? –

+0

표준입니다. 너를 위해 아프다. 잠깐만. –

+0

하지만 잠재적 인 변환이 가장 가까운 트리를 검색하지 않는 이유는 해석하지 않습니다. –

0

.. 이것은 또한 기본 형식 사이의 변환을 포함하는 경우, 그들은 당신이 test(B)의 경우에 당신이 자리에 두 개의 변환을 경우에도 포함되지 않지만, 다음은 컴파일되지 않습니다 :

class B 
{ 
public: 
    B(int) {} 
}; 

class A 
{ 
public: 
    A(const B&) {} 
}; 

void test(const A&) {} 

.... 

test(5); 

는 암시 적 변환을하고 컴파일러를 사용하지 않으려면 0123을 사용해야합니다.생성자가 포함 된 키워드