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++? Есть ли другое объяснение? Благодарю.
2 ответа
'void a(foo)' [найдено с использованием аргумент-зависимого поиска]
Что ж, на удивление у MSVC есть очень хорошее объяснение ошибки:
Следуя стандарту, внутри функции компилятор ищет символы в текущем пространстве имен и в пространстве имен, где определен тип аргументов.
В первом случае a
в foobar
и в пространстве имен типа аргумента foo
: глобальное пространство имен, что делает его неоднозначным.
Во втором случае a
в foobar
но не в пространстве имен типа аргумента bar::foo
с bar
,
Есть два символа a(foo), и компилятор не может решить, какой из них использовать. Следовательно, вы должны явно указать компилятору.
Если вы хотите, чтобы (foo) из foobar был вызван, попробуйте это,
void b(foo f) { foobar::a(f); }
если вы хотите глобальный (foo), попробуйте это,
void b(foo f) { ::a(f); }