2013-04-12 61 views
3

首先,這個問題純粹是理論性的。我不是在尋找解決方案(我已經知道了),我只是在尋找解釋。C++奇怪的模糊調用重載函數

下面的代碼不編譯:

struct foo {}; 
void a(foo) {} 
namespace foobar { 
    void a(foo) {} 
    void b(foo f) {a(f);} 
} 
int main() {return 1;} 

MSVC++:

1>c:\projects\codetests\main.cpp(7) : error C2668: 'foobar::a' : ambiguous call to overloaded function 
1>  c:\projects\codetests\main.cpp(4): could be 'void foobar::a(foo)' 
1>  c:\projects\codetests\main.cpp(2): or  'void a(foo)' [found using argument-dependent lookup] 
1>  while trying to match the argument list '(foo)' 

G ++:

main.cpp: In function 'void foobar::b(foo)': 
main.cpp:5:20: error: call of overloaded 'a(foo&)' is ambiguous 
main.cpp:5:20: note: candidates are: 
main.cpp:4:7: note: void foobar::a(foo) 
main.cpp:2:6: note: void a(foo) 

儘管此代碼編譯(MSVC++和G ++):

namespace bar {struct foo {};} 
void a(bar::foo) {} 
namespace foobar { 
    void a(bar::foo) {} 
    void b(bar::foo f) {a(f);} 
} 
int main() {return 1;} 

這是爲什麼?這個編譯器的foo命名空間在這裏改變了什麼?這種行爲是在C++標準中定義的嗎?還有其他解釋嗎?謝謝。

+0

第一種情況有兩種可能的匹配,導致錯誤。您在第二種情況下刪除了這兩種可能的匹配中的一種,消除了錯誤。什麼是神祕? –

+0

乳清在第二種情況下是否刪除了一個可能的配對?還有:: a(bar :: foo)和foobar :: a(bar :: foo)。你看到了這個謎團? – florian

回答

2

「無效a(foo)'[使用參數依賴型查找找到]

嗯,令人驚訝的是,MSVC有一個非常好的錯誤說明:

遵循標準,在函數內部,編譯器在當前命名空間和參數類型定義的命名空間中尋找符號。

在第一種情況下afoobar和參數類型foo的命名空間:全局名稱空間,使其不明確。

在第二種情況下,afoobar中,但不在參數類型bar::foo的命名空間中:with is bar

+0

+1感謝您的解釋。 – florian

0

有兩個符號a(foo),編譯器無法決定使用哪一個符號。 因此你必須明確地指示編譯器。

如果你想foobar的的(富)到被調用那就試試這個,

void b(foo f) { foobar::a(f); } 
如果你想全局一(富)

那就試試這個,

void b(foo f) { ::a(f); } 
+0

是的,我知道。但問題是爲什麼第二個例子編譯,第一個例子不是。唯一的區別是struct foo周圍的命名空間。 – florian