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]
clang++ 3.4:
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..
You can't call a function without declaring it first. It's how it works in C++..
It is always recommended to declare a function before its use so that we don't see any surprises when the program is run (See this for more details).
Actually, it is not required that a function be declared before use in C. If it encounters an attempt to call a function, the compiler will assume a variable argument list and that the function returns int.
Function declaration is required when you define a function in one source file and you call that function in another file. In such case, you should declare the function at the top of the file calling the function.
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!
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