13 Templates [temp]

13.7 Name resolution [temp.res]

13.7.4 Dependent name resolution [temp.dep.res]

13.7.4.1 Point of instantiation [temp.point]

For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization.
Otherwise, the point of instantiation for such a specialization immediately follows the namespace scope declaration or definition that refers to the specialization.
If a function template or member function of a class template is called in a way which uses the definition of a default argument of that function template or member function, the point of instantiation of the default argument is the point of instantiation of the function template or member function specialization.
For a noexcept-specifier of a function template specialization or specialization of a member function of a class template, if the noexcept-specifier is implicitly instantiated because it is needed by another template specialization and the context that requires it depends on a template parameter, the point of instantiation of the noexcept-specifier is the point of instantiation of the specialization that requires it.
Otherwise, the point of instantiation for such a noexcept-specifier immediately follows the namespace scope declaration or definition that requires the noexcept-specifier.
For a class template specialization, a class member template specialization, or a specialization for a class member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization, if the context from which the specialization is referenced depends on a template parameter, and if the specialization is not instantiated previous to the instantiation of the enclosing template, the point of instantiation is immediately before the point of instantiation of the enclosing template.
Otherwise, the point of instantiation for such a specialization immediately precedes the namespace scope declaration or definition that refers to the specialization.
If a virtual function is implicitly instantiated, its point of instantiation is immediately following the point of instantiation of its enclosing class template specialization.
An explicit instantiation definition is an instantiation point for the specialization or specializations specified by the explicit instantiation.
A specialization for a function template, a member function template, or of a member function or static data member of a class template may have multiple points of instantiations within a translation unit, and in addition to the points of instantiation described above,
A specialization for a class template has at most one point of instantiation within a translation unit.
A specialization for any template may have points of instantiation in multiple translation units.
If two different points of instantiation give a template specialization different meanings according to the one-definition rule, the program is ill-formed, no diagnostic required.

13.7.4.2 Candidate functions [temp.dep.candidate]

For a function call where the postfix-expression is a dependent name, the candidate functions are found using the usual lookup rules from the template definition context ([basic.lookup.unqual], [basic.lookup.argdep]).
Note
:
For the part of the lookup using associated namespaces ([basic.lookup.argdep]), function declarations found in the template instantiation context are found by this lookup, as described in [basic.lookup.argdep].
— end note
 ]
If the call would be ill-formed or would find a better match had the lookup within the associated namespaces considered all the function declarations with external linkage introduced in those namespaces in all translation units, not just considering those declarations found in the template definition and template instantiation contexts, then the program has undefined behavior.
Example
:

Source file "X.h":

namespace Q {
  struct X { };
}

Source file "G.h":

namespace Q {
  void g_impl(X, X);
}

Module interface unit of M1:

module;
#include "X.h"
#include "G.h"
export module M1;
export template<typename T>
void g(T t) {
  g_impl(t, Q::X{ });   // ADL in definition context finds Q​::​g_­impl, g_­impl not discarded
}

Module interface unit of M2:

module;
#include "X.h"
export module M2;
import M1;
void h(Q::X x) {
   g(x);                // OK
}
— end example
 ]
Example
:

Module interface unit of Std:

export module Std;
export template<typename Iter>
void indirect_swap(Iter lhs, Iter rhs)
{
  swap(*lhs, *rhs);     // swap not found by unqualified lookup, can be found only via ADL
}

Module interface unit of M:

export module M;
import Std;

struct S { /* ...*/ };
void swap(S&, S&);      // #1

void f(S* p, S* q)
{
  indirect_swap(p, q);  // finds #1 via ADL in instantiation context
}
— end example
 ]
Example
:

Source file "X.h":

struct X { /* ... */ };
X operator+(X, X);

Module interface unit of F:

export module F;
export template<typename T>
void f(T t) {
  t + t;
}

Module interface unit of M:

module;
#include "X.h"
export module M;
import F;
void g(X x) {
  f(x);             // OK: instantiates f from F,
                    // operator+ is visible in instantiation context
}
— end example
 ]
Example
:

Module interface unit of A:

export module A;
export template<typename T>
void f(T t) {
  cat(t, t);         // #1
  dog(t, t);         // #2
}

Module interface unit of B:

export module B;
import A;
export template<typename T, typename U>
void g(T t, U u) {
  f(t);
}

Source file "foo.h", not an importable header:

struct foo {
  friend int cat(foo, foo);
};
int dog(foo, foo);

Module interface unit of C1:

module;
#include "foo.h" // dog not referenced, discarded
export module C1;
import B;
export template<typename T>
void h(T t) {
  g(foo{ }, t);
}

Translation unit:

import C1;
void i() {
   h(0);        // error: dog not found at #2
}

Importable header "bar.h":

struct bar {
  friend int cat(bar, bar);
};
int dog(bar, bar);

Module interface unit of C2:

module;
#include "bar.h" // imports header unit "bar.h"
export module C2;
import B;
export template<typename T>
void j(T t) {
  g(bar{ }, t);
}

Translation unit:

import C2;
void k() {
   j(0);        // OK, dog found in instantiation context:
                // visible at end of module interface unit of C2
}
— end example
 ]