I'm having trouble understanding the rules behind argument-dependent (Koenig) lookup.
Consider the code below:
#include <iostream>
using namespace std;
namespace adl
{
struct Test { };
void foo1(Test const &) { cout << "ADL used (foo1)" << endl; }
void foo2(Test const &) { cout << "ADL used (foo2)" << endl; }
void foo3(Test const &) { cout << "ADL used (foo3)" << endl; }
}
struct foo1
{
foo1() { }
template<class T>
foo1(T const &) { cout << "ADL not used (foo1)" << endl; }
template<class T>
void operator()(T const &) const { cout << "ADL not used (foo3)" << endl; }
};
template<class T> void foo2(T const &)
{ cout << "ADL not used (foo2)" << endl; }
int main()
{
adl::Test t;
foo1 foo3;
(foo1(t));
(foo2(t));
(foo3(t));
}
Its output is:
ADL not used (
foo1
)
ADL used (foo2
)
ADL not used (foo3
)
I expected all of them to use ADL, but I was surprised that only some of them did.
What are the (potentially gory, I know) details behind the rules of ADL?
I understand the concept well enough, but the details are what I'm having trouble with.
Which scopes are searched, when are they searched, and when are they not searched?
Is it at all possible to tell whether ADL is used without having to look through all the #include
'd files before the given line of code? I expected functors and functions to behave the same way in terms of [not] masking ADL, but apparently they don't.
Is there any way to force ADL in cases where it is not done automatically (such as the above) and you don't know the class's namespace (e.g. in a template)?
Your problem isn't really with argument dependent lookup. First of all, argument dependent lookup only possibly enters the picture when doing unqualified looking up of functions. When calling foo1(t)
foo1
is a type and its templated constructor is called. Similarly, foo3(t)
is a qualified lookup because foo3
is an object and the function call operator is looked up in the object's class foo1
. The only place where argument lookup enters the picture is calling foo2(t)
where lookup finds to candidates:
::foo2<adl::Test>(adl::Test const&)
::adl::foo2(adl::Test const&)
These two functions are handed off to overload resolution and since both functions are equally good matches the non-template function wins.
Your question are actually three questions:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With