简体   繁体   中英

C++20 modules export template instantiation

I'm creating a library and I have a class template inside a C++20 module and I want to add an instantiation in order to reduce compilation time for every project that uses my library.

Are these different implementations equivalent, or is there a better way to achieve it?

1)

//mod.cpp
export module mod;

export template<typename T>
struct mystruct{ T i;};

export template class mystruct<int>;
//mod.cpp
export module mod;

export template<typename T>
struct mystruct{ T i;};

template class mystruct<int>;
//mod.cpp
export module mod;

export template<typename T>
struct mystruct{ T i;};

export extern template class mystruct<int>;



//mod_impl.cpp
module mod;

template class mystruct<int>;

Edit : This answer says only that 2. works, but my point is if also 1. and 3. are equivalent to 2.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM