10 Modules [module]

10.6 Instantiation context [module.context]

The instantiation context is a set of points within the program that determines which declarations are found by argument-dependent name lookup ([basic.lookup.argdep]) and which are reachable ([module.reach]) in the context of a particular declaration or template instantiation.
During the implicit definition of a defaulted function ([special], [class.compare.default]), the instantiation context contains each point in the instantiation context from the definition of the class and each point in the instantiation context of the program construct that resulted in the implicit definition of the defaulted function.
During the implicit instantiation of a template whose point of instantiation is specified as that of an enclosing specialization ([temp.point]), the instantiation context contains each point in the instantiation context of the enclosing specialization and, if the template is defined in a module interface unit of a module M and the point of instantiation is not in a module interface unit of M, the point at the end of the declaration-seq of the primary module interface unit of M (prior to the private-module-fragment, if any).
During the implicit instantiation of a template that is implicitly instantiated because it is referenced from within the implicit definition of a defaulted function, the instantiation context contains each point in the instantiation context of the defaulted function.
During the instantiation of any other template specialization, the instantiation context contains the point of instantiation of the template.
During the implicit instantiation of any construct that resulted from the evaluation of an expression as a core constant expression, the instantiation context contains each point in the evaluation context ([expr.const]).
[Note 1: 
Implicit instantiations can result from invocations of library functions ([meta.reflection]).
The evaluation context can include synthesized points associated with injected declarations produced by std​::​meta​::​define_aggregate ([meta.reflection.define.aggregate]).
— end note]
In any other case, the instantiation context at a point within the program contains that point.
The instantiation context contains only the points specified above.
[Example 1: 

Translation unit #1:export module stuff; export template<typename T, typename U> void foo(T, U u) { auto v = u; } export template<typename T, typename U> void bar(T, U u) { auto v = *u; }

Translation unit #2:export module M1; import "defn.h"; // provides struct X {}; import stuff; export template<typename T> void f(T t) { X x; foo(t, x); }

Translation unit #3:export module M2; import "decl.h"; // provides struct X; (not a definition) import stuff; export template<typename T> void g(T t) { X *x; bar(t, x); }

Translation unit #4:import M1; import M2; void test() { f(0); g(0); }

The call to f(0) is valid; the instantiation context of foo<int, X> comprises
  • the point at the end of translation unit #1,
  • the point at the end of translation unit #2, and
  • the point of the call to f(0),
so the definition of X is reachable ([module.reach]).
It is unspecified whether the call to g(0) is valid: the instantiation context of bar<int, X> comprises
  • the point at the end of translation unit #1,
  • the point at the end of translation unit #3, and
  • the point of the call to g(0),
so the definition of X need not be reachable, as described in [module.reach].
— end example]