Question

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.

Was it helpful?

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.

OTHER TIPS

There are two symbols a(foo) and compiler can't decide which one to use. Hence you have to explicitly instruct the compiler.

If you want a(foo) of foobar to get invoked then try this,

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

if you want global a(foo) then try this,

   void b(foo f) { ::a(f); }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top