Contrary to my expectations, this program works:
#include <iostream>
namespace a { struct item{}; }
namespace b { struct item{}; }
template<typename T>
void func(T t) { do_func(t); }
int main()
{
func(a::item{});
func(b::item{});
}
namespace a { void do_func(item) { std::cout << "a::func\n"; } }
namespace b { void do_func(item) { std::cout << "b::func\n"; } }
Output:
a::func
b::func
Verifications with online compilers:
If the instantation of func<T>
occurs in the body of main
then I would expect that a::do_func
and b::do_func
are not yet declared.
How can this work?
According to @Marc Claesen the reason that above works is:
template instantiation is performed after reading all of the source
However, then why does this code does not work:
#include <iostream>
template<typename T>
void func(T t) { do_func(t); }
int main()
{
func(1);
}
void do_func(int) { std::cout << "do_func(int)\n"; }
See gcc-4.8:
error: 'do_func' was not declared in this scope,
and no declarations were found by argument-dependent
lookup at the point of instantiation [-fpermissive]
error: call to function 'do_func' that is neither
visible in the template definition nor found by
argument-dependent lookup
So it seems that the combination of function template and ADL are required to make it work.
However, I don't understand why this is so..
It works because of two interesting things:
Have a look at this:
In short, do_func
is a dependent name, so in the first phase (when the file is only parsed but the function template is not instantiated) the compiler does not resolve the name do_func
, it only checks the syntax and it sees it is a valid function call. That is all. In the second phase when the function template is instantiated (and thus T
is known), the name do_func
is resolved and at this time it also uses ADL to lookup the name.
Note that ADL works only for user-defined types. It doesn't work for built-in types, which is why your second code (i.e func(1)
) doesn't work!