2013-04-12 8 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 имеет очень хорошее объяснение ошибок :

Следуя стандарту, внутри функции компилятор ищет символы в текущем пространстве имен и в пространстве имен, где определены типы аргументов.

В первом случае a находится в foobar и в пространстве имен аргумента типа foo: глобальное пространство имен, что делает его неоднозначным.

Во втором случае a в foobar, но не в пространстве имен типа аргумента bar::foo: с bar это.

+0

+1 Спасибо за объяснение. – florian

0

Существует два символа a (foo), и компилятор не может решить, какой из них использовать. Следовательно, вы должны явно проинструктировать компилятор.

Если вы хотите (Foo) из Foobar, чтобы ссылаться затем попробовать это,

void b(foo f) { foobar::a(f); } 

если вы хотите глобальный а (Foo), то попробуйте это,

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

Да, я это знаю. Но вопрос в том, почему второй пример компилируется, а первый нет. Единственное отличие - пространство имен вокруг struct foo. – florian

Смежные вопросы