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)你知道他們對那些認爲他們的bug是編譯器bug的人的評價,以及(b)這看起來像是一個非常明顯的錯誤,它們在一致性測試期間會發出紅旗。

這是一個不兼容的MSVC或不兼容的GCC? (或兩者?)我的理由是超負荷分辨率的聲音?

+1

我不知道哪個編譯器是正確的,但作爲一個人,我更喜歡知道使用哪個重載,而不必基於兩種類型轉換的「優先級」來消除歧義:-) – Cameron 2014-09-02 13:18:29

+0

@Cameron哦,我同意。實際的用例更有意義,並且*看起來*毫不含糊。 – Sneftel 2014-09-02 13:24:45

回答

7

MSVC是正確的。

GCC 4.9.0說:

警告:ISO C++說,這些都是不明確的,即使第一個最壞的轉換比第二最壞的轉換更好:默認情況下啓用]

叮噹3.4.1同意這兩個函數是不明確的。

雖然B* => B*B* => B const*都有完全匹配排名,前者仍是每over.ics.rank/3更好的轉換序列;這是(例如每),以確保:

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

謝謝。那麼我的推理有什麼缺陷?從我讀的標準看來,沒有針對重載2的轉換,這比重載1的相應轉換更糟 - 編譯器在比較過載時不應該將'B *'更改爲'B const *'。 – Sneftel 2014-09-02 13:23:38

+0

@Sneftel啊,但它確實 - 我會添加確切的措辭。 – ecatmur 2014-09-02 13:31:22

+0

葉剛纔發現。看起來我太早停止閱讀了。感謝您的挖掘。 – Sneftel 2014-09-02 13:36:40