2013-04-12 35 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