The strange part is not that the int
example fails to compile, it is that the type
example does since bar
is defined after foo
. This is due to [temp.dep.candidate] (see third paragraph).
Two-pass compilation of templates
When the compiler parses and compiles a template class or function, it looks up identifiers in two pass:
- Template argument independent name lookup: everything that does not depend on the template arguments can be checked. Here, since
bar()
depends on a template argument, nothing is done. This lookup is done at the point of definition.
- Template argument dependent name lookup: everything that could not be looked up in pass #1 is now possible. This lookup is done at the point of instantiation.
You get an error during pass #2.
ADL lookup
When a function name is looked up, it is done within the current context and those of the parameters type. For instance, the following code is valid though f
is defined in namespace n
:
namespace n { struct type {}; void f(type) {}; }
int main() { n::type t; f(t); } // f is found in ::n because type of t is in ::n
More about ADL (cppreference.com):
Argument-dependent lookup, also known as ADL, or Koenig lookup, is the set of rules for looking up the unqualified function names in function-call expressions, including implicit function calls to overloaded operators. These function names are looked up in the namespaces of their arguments in addition to the scopes and namespaces considered by the usual unqualified name lookup.
Two-pass compilation, ADL lookup and unqualified-id lookup
In your case, those three mechanisms collide. See [temp.dep.candidate]:
For a function call that depends on a template parameter, if the function name is an unqualified-id but not a template-id, the
candidate functions are found using the usual lookup rules (3.4.1,
3.4.2) except that:
— For the part of the lookup using unqualified name lookup (3.4.1), only function declarations with external linkage from the
template definition context are found.
— For the part of the lookup using associated namespaces (3.4.2), only function declarations with external linkage found in either the
template definition context or the template instantiation context are
found.
So, with foo(type())
unqualified-id lookup kicks in and the lookup is done "in either the template definition context or the template instantiation".
With foo(42)
, 42
being a fundamental type, ADL is not considered and only the "definition context" is considered.
bar()
to the top of the file makes the example work. – Lookeronint
and a user defined type? – Subserveint
is a fundamental type (second list, first point). – Cornet