Why do g ++ and clang violate namespace abstraction in this case?

This compiles:

struct str {}; namespace a { void foo(str s) {} } namespace b { void foo(str s) {} void bar(str s) { foo(s); } } int main(int, char**) { return 0; } 

but this is not the case (with a structure definition moved inside the namespace a)

 namespace a { struct str {}; void foo(str s) {} } namespace b { void foo(a::str s) {} void bar(a::str s) { foo(s); } } int main(int, char**) { return 0; } 

The error I get is

 bad.cpp: In function 'void b::bar(a::str)': bad.cpp:12: error: call of overloaded 'foo(a::str&)' is ambiguous bad.cpp:10: note: candidates are: void b::foo(a::str) bad.cpp:5: note: void a::foo(a::str) 

It seems reasonable to expect that since a :: foo does not matter, a call to foo can only refer to b :: foo. Is there a good reason for compilation failure (and if so, what is it), or is it a lack of implementations (of both the main compilers)?

+4
source share
1 answer

This is due to the way name lookup, and in particular, Search for Dependent Arguments (ADL) , works. When you decide which functions can be a candidate for allowing your call, the compiler first looks for names in:

  • The namespace in which the function is called;
  • The namespace in which the types of argument (s) are defined.

If no function with this name is found in these namespaces, the compiler will continue to check the parent namespace of the namespace in which the call is made.


So what happens in the examples from your question?

In the first case, str is defined in the global namespace, and there is no function named foo() . However, there is one ( b ) in the namespace where the call is made: therefore, the compiler found the correct name, stopped searching for names, and overload resolution began.

But well, there is only one candidate function! So, the task here is simple: the compiler calls b::foo() .

In the second case, on the other hand, str is defined in the namespace a , and when foo(s) called, the compiler will again search in the namespace where call ( b ) is performed and in the namespace where the argument type ( str ) is specified - on this time a .

So now there are two functions with matching names for call resolution: enter overload resolution! Alas, both functions are equally good (exact matches, no conversion needed). Consequently, the challenge is ambiguous.

+7
source

All Articles