16

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?

Update

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..

StackedCrooked
  • 34,653
  • 44
  • 154
  • 278

1 Answers1

15

It works because of two interesting things:

  • two-phase name lookup which is performed to lookup dependent names.
  • and Argument Dependent Lookup (ADL).

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!

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Right, one should test it on VC++2010 to prove. – SChepurin May 18 '13 at 11:25
  • 1
    Can you justify that the selected specialization is well-formed at each point of instantiation? – Luc Danton May 18 '13 at 12:40
  • @LucDanton: I didn't understand your question. Could you rephrase it? – Nawaz May 18 '13 at 12:42
  • This [slightly modified program](http://coliru.stacked-crooked.com/view?id=da858a1d050013e0dc62ee3ffb62c698-7063104e283ed82d51a6fde7370c6e59) is rejected by Clang, although not GCC: when the (this time) explicit instantiation takes place, there is no overload of `do_func` yet declared to be found by ADL. What is the difference when the instantiation is implicit? – Luc Danton May 18 '13 at 13:03
  • LucDanton: Hmm. I've to dig the spec more to find an answer to that. Lets see if I find one. Maybe, [@Johannes](http://stackoverflow.com/users/34509/johannes-schaub-litb) can help us. – Nawaz May 18 '13 at 13:22