2012-08-09 66 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

因爲重載具有兩個同樣可行函數(既具有用戶定義的轉換)選擇您得到一個錯誤。函數重載解析是一個非常複雜的主題。有關過載分辨率的更多詳細信息,請參閱Stephan T. Lavavej的recent lecture。通常最好使用單參數構造函數explicit,然後使用顯式構造函數參數調用您的函數。

test(0L)與任何過載都不完全匹配,因爲沒有過載test(long)。您提供的兩個重載都在其參數上有用戶定義的轉換,但編譯器認爲它們同樣可行。 A過載必須執行標準轉換(long轉換爲int),後跟用戶定義的轉換(int轉換爲A),並且B將用戶定義的轉換(long轉換爲B)進行重載。但都是隱式用戶定義的轉換序列

這些排名如何?標準說在13.3.3.2排名的隱式轉換的序列[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

這些類型的例如平局決勝如果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 2012-08-09 09:51:30

+0

@rhalbersma:但我認爲測試(0L)更準確地匹配測試(B b)?爲什麼不明確? – 2012-08-09 09:54:53

+0

'0L'是'long',所以你的第二段應該說「沒有'test(long)'」。 – Xeo 2012-08-09 10:01:20

0

試試這個:

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

關鍵字明確停止編譯器做隱式轉換。

1

函數重載考慮確切的參數類型或隱式轉換。 在您的示例中,從重載的角度來看,備選方案A(0L)和B(0L)都是相同的,因爲需要隱式構造函數調用。

1

您正在使用long類型的參數調用測試。

沒有測試(長)。

編譯器必須在測試(A)和測試(B)之間進行選擇。

爲了調用測試(A)它具有長轉換序列 - > INT - > A.

爲了調用測試(B)它具有長轉換序列 - > B.

根據在標準的排名規則中,如果一個排名比另一個排名靠前,那麼它將選擇一個排名規則 - 否則它會以模糊不清的方式失敗。

在這個特定情況下,兩個轉換序列的排列是相同的。

還有就是在標準規定它是如何計算轉換序列的部分排名一長串13.3.3最佳可行函數」

+0

和規則在哪裏? – 2012-08-09 09:57:11

+0

在標準中。生病了,請繼續看。 – 2012-08-09 09:57:36

+0

但它並不解釋爲什麼不搜索最近的潛在轉換樹。 – 2012-08-09 10:07:50

0

編譯器允許這樣做只有一個隱式轉換到用戶類型如果這還涉及到基本類型之間的轉換,他們不指望即使你在test(B)情況下,你擁有兩個轉換,但下面不會編譯:

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

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

void test(const A&) {} 

.... 

test(5); 

要禁用編譯器做你的隱式轉換應該使用explicit關鍵字與構造

相關問題