Search code examples
c++namespacescompiler-theoryambiguous

C++ strange ambiguous call to overloaded function


First of all, this question is purely of theoretical nature. I am not searching for a solution (I already know it), I am just searching for an explanation.

The following code doesn't compile:

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)

While this code compiles (MSVC++ and 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;}

Why is that? What does the namespace around foo change for the compiler here? Is this behaviour defined in the C++-Standard? Is there any other explanation? Thanks.


Solution

  • 'void a(foo)' [found using argument-dependent lookup]

    Well, surprisingly MSVC has a very good error explanation:

    Following the standard, inside a function the compiler look for symbols in the current namespace and in the namespace where the type of the arguments are defined.

    In the first case a is in foobar and in the namespace of the argument type foo: the global namespace, making it ambiguous.

    In the second case a is in foobar but not in the namespace of the argument type bar::foo: with is bar.