c++c++11templatesexternexplicit-instantiation

extern template declaration with alias payload


Consider this. There is a class Derived that inherits from some instantiation of a heavy templated class Base, and there are many uses of Derived in various source files. So it is reasonable to have only one Derived-specific instantiation of Base.

C++11 allows this via extern template, but the problem here is that I want to type the Derived-specific instantiation of Base only once. Technically it is possible, as Derived can hold an alias for that instantiation, but the question is: will it still force the compiler not to instantiate the template?

Here is the try:

// Base.hpp
template < typename Arg > struct Base { using TheArg = Arg; };

// Derived.hpp
#include "Base.hpp"
struct Derived : Base<int> { };
// The next line will be huge in real-world scenario, so I want to avoid it.
// extern template struct Base<int>;
// Instead I want this.
extern template struct Base<Derived::TheArg>;

// Derived.cpp
#include "Derived.hpp"
template struct Base<Derived::TheArg>;

// Use01.cpp
#include "Derived.hpp"
void use01() { Derived dd; }

The point here is to force Use01.cpp not to instantiate Base<int> and to refer to the explicit instantiation at Derived.cpp instead.

I am compiling with gcc-v9.3 and the questions are:

  1. Does extern template declaration takes effect to all instantiations in the translation unit, or only to those which appear after its declaration?
  2. Will using Derived::TheArg instead of int cause any problems with deferring the instantiation?

Putting the extern template declaration at the end of Use01.cpp and commenting out the explicit instantiation at Derived.cpp makes the compilation to fail, so this gives me some confidence that the extern template declaration doesn't have to appear before any instantiation, so the second question still makes sense.


Solution

  • An explicit instantiation declaration of a specialization of a class template doesn’t prevent instantiating that specialization. After all, you still need to be able to refer to members of the resulting class, which means knowing everything about its layout. What it does do is prevent instantiation of its (non-inline) member functions, so that no code need be emitted for them.

    Additionally, an explicit instantiation declaration must precede any source of implicit instantiation to be effective. If you want to name that specialization’s template argument just once, introduce a type alias for it before the explicit instantiation declaration and the definition of Derived.