Modules affect 2 things: the scope of names and the reach-ability of declarations. Both of these only matter if they are within the purview of a module (ie: in an imported module interface TU and not being in the global module fragment).
Names declared in the purview of a module can be used outside of that module only if they are export
ed by that module. In the case of an explicit template instantiation, the template itself is already exported, so users outside of the module can already use the name.
However, an explicit template instantiation definition is also a declaration. And modules control the reach-ability of declarations. The thing is, the rules of reach-ability for a declaration don't actually care about export
:
A declaration D is reachable if, for any point P in the instantiation context ([module.context]),
- D appears prior to P in the same translation unit, or
- D is not discarded ([module.global.frag]), appears in a translation unit that is reachable from P, and does not appear within a private-module-fragment.
[ Note: Whether a declaration is exported has no bearing on whether it is reachable. — end note ]
Emphasis added.
These rules only care about which TUs have been imported (and whether the declaration is in a global/private module fragment).
Therefore, if the primary template declaration was export
ed, an explicit template instantiation (that is not in the global/private module fragment) in one of the imported module files is reach-able by any code that imports it.
So it doesn't matter if you export
an explicit template instantiation. If the primary template was already export
ed, its name could already be used, so the only thing that matters is if the explicit template instantiation is visible.
So your #1 and 2 are functionally equivalent. And its best not to export
something you don't need to.
As for the behavior of extern template
, that's interesting.
While extern
normalize denotes external linkage, this does not apply to extern template
. So we don't have linkage problems. And since the extern template
declaration is reach-able by importers of the module (as previously stated), they'll see it and respect it.
So the only question is whether the explicit definition in your "mod_impl.cpp" is also reach-able. Except that's not a question because only the declaration part of a definition is ever "reach-able". That is, reach-ability only matters for a declaration.
The explicit instantiation definition is in a different TU. Therefore, it will only be instantiated in that TU; code which imports the module reaches only the declaration. And therefore, it won't instantiate the template.
So yes, you can perform extern template
gymnastics (though again, export
doesn't matter). But it's no different than just putting the explicit instantiation in your module interface, and it's way cleaner to do that.