0

In Wikipedia article below quote is mentioned:

ADL only occurs if the normal lookup of an unqualified name fails to find a matching class member function. In this case, other namespaces not considered during normal lookup may be searched where the set of namespaces to be searched depends on the types of the function arguments.

So, I was expecting below program would compile fine, but it doesn't:

namespace N1 {
  class A {}; 
  void foo (A *p) {}
}
namespace N2 {
  void foo (N1::A &p) {}
}

int main () {
  N1::A xa; 
  foo(&xa); // ok
  foo(xa);  // error: cannot convert ‘N1::A’ to ‘N1::A*’ for argument ‘1’ to ‘void N1::foo(N1::A*)’
}

I searched several questions in SO, but couldn't find which lists the requirements or situations in simple word which suggests: When the ADL kicks in ?
A little more detailed answer would be really helpful to me and future visitors.

iammilind
  • 68,093
  • 33
  • 169
  • 336

5 Answers5

4

It shouldn't compiles. A is in namespace N1. How compiler should knows, that you want to call N2::foo? n3376 3.4.2/2

For each argument type T in the function call, there is a set of zero or more associated namespaces and a set of zero or more associated classes to be considered. The sets of namespaces and classes is determined entirely by the types of the function arguments (and the namespace of any template template argument). Typedef names and using-declarations used to specify the types do not contribute to this set. The sets of namespaces and classes are determined in the following way:

If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces of which any template template arguments are members; and the classes of which any member templates used as template template arguments are members. [ Note: Non-type template arguments do not contribute to the set of associated namespaces. — end note ]

ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • I would like to know which requirement in suggested wiki article this program is not fulfilling ? – iammilind Feb 22 '13 at 08:39
  • @iammilind `N2` is not associated in any way with any of the arguments you pass to `foo`, so the compiler has no reason to add `N2` to the set of associated namespaces. – James Kanze Feb 22 '13 at 08:44
  • 1
    @iammilind Wikipedia is not the standard. The standard is the standard. And it unambiguously (albeit in a convoluted way) defines rules for which namespaces to consider. `N2` doesn't fall under any of those rules. – Angew is no longer proud of SO Feb 22 '13 at 08:54
  • @iammilind As Angew says, Wikipedia is not the standard, but it's still right here. The problem you have here is that you're expecting ADL to do something that it doesn't. Yes, ADL is invoked, but it's not going to find `N2::foo`. It is ADL that allows `N1::foo` to work. – Joseph Mansfield Feb 22 '13 at 09:09
1

ADL kicks in pretty much always, as soon as your function takes user a user defined type. It's kicking in for foo here: xa is defined in N1, so foo is searched in N1 as well as in the global namespace. (Without ADL, foo would only be searched in the global namespace.)

And I don't see why you would expect the second call to foo to compile. The type of xa is defined in N1, so ADL adds N1 to the search path, but there's nothing in the expression to imply N2.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • The 2nd line of quoted wiki passage, confuses me. It says other namespaces will be considered. There is also an example of `operator <<` in the same article. – iammilind Feb 22 '13 at 08:44
  • 1
    @iammilind: Other namespaces are considered. Namely `N1`. ADL basically considers the namespaces containing one of the argument types – Grizzly Feb 22 '13 at 08:46
  • @iammilind I have no idea about the Wiki passage. The standard speaks of "zero or more associated namespaces" for each argument. In this case, `N1` is an associated namespace for `xa`, and is searched (which it wouldn't be without ADL). There is no association for `N2`, however. – James Kanze Feb 22 '13 at 09:30
1

It says "other namespaces" are searched. It doesn't say "all namespaces" are searched.

The rules for what extra namespaces are included in ADL are a little complicated, but the most important one is the namespace in which A is defined. That's why your first foo is found. Your second foo can't be found because namespace N2 is nothing to do with anything, and it is not searched by ADL.

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
1

If unqualified Name Look-up fails, then look-up proceeds using the argument of the function's call.

Example

func(A x);

Then compiler will look at namespace up starting at namespace including class A. One example is this

// argument_dependent_name_koenig_lookup_on_functions.cpp
namespace A
{
   struct X
   {
   };
   void f(const X&)
   {
   }
}
int main()
{
// The compiler finds A::f() in namespace A, which is where 
// the type of argument x is defined. The type of x is A::X.
   A::X x;
   f(x);   
}

More here http://msdn.microsoft.com/en-us/library/60bx1ys7.aspx

kiriloff
  • 25,609
  • 37
  • 148
  • 229
0

The compiler stops lookup once he has found a function with a matching name. It does not continue searching if the argument types or accessibility (public/protected/private) actually prevent using the function in the current context. Hence in your example, the compiler has no change to "see" N2::foo, since N1::foo is found first.

Note that in your example, N2::foo wouldn't be found even if N1::foo did not exist, as you have no reference to N2 anywhere inside main, so N2 will not be searched at all.

JohnB
  • 13,315
  • 4
  • 38
  • 65
  • 3
    Even without `N1::foo`, the compiler will not see `N2::foo`, as there is nothing to cause it to look in `N2`. – James Kanze Feb 22 '13 at 08:42
  • That's not how ADL works, read the quoted passage in ForEveR's answer. – Jesse Good Feb 22 '13 at 08:48
  • Declaration of `foo` in namespace `N1` will prevent detection of `foo` in any other namespace that's potentially searched (hence `N2::foo` won't be found even if you add a `using namespace N2;` inside main). – JohnB Feb 22 '13 at 08:52