Continued form C++ shared library & templates

Here we’ll look at how template functions become linked together when a shared library & header expose a template function to use.

We will create a library liba.so from the file a.cpp. The header exposed by the shared library is a.h. Let’s look at the contents of the files:

a.h:

template<typename T>
T f() {}

a.cpp:

#include "a.h"
 
template void f<void>();
 
void foo() { f<void>(); }

The (relevant) symbols present in liba.so are:

0000000000001100 W void f<void>()
00000000000010f0 T foo()

Note that “W” indicates a Weak Symbol.

The user of the shared library is b.cpp:

#include "a.h"
 
int main() {
	f<void>();
}

And the relevant symbols in the final binary (with the shared library linked) are:

0000000000001129 W void f<void>()

Observe that even though our liba.so has explicitly instantiated f<void>, the binary still has the definition of f<void> present.

If we add the following line to b.cpp:

extern template void f<void>();

Then the symbol becomes:

                 U void f<void>()

The extern declaration makes the type of the symbol as Undefined, means it will be provided through somewhere else. If there is no explicit instantiation of f<void> in liba.so, there will be no defined symbol available and linking will fail. Also see C++ extern - Explicit template instantiation