In an effort to reduce compilation times in a large project that makes liberal use of templates, I've had good results using "extern template" (explicit template instantiation) to prevent common template functions from being defined in many different compilation units.
However, one annoying thing about it is that it doesn't work for member functions defined within the class definition.
For example, I have the following template class:
template <typename T>
struct Foo
{
static T doubleIt(T input)
{
return input * 2;
}
};
Now, I know that Foo is most commonly used for numeric types, so I add this to the header:
extern template struct Foo<int>;
extern template struct Foo<float>;
extern template struct Foo<double>;
And in a cpp file, add explicit instantiations:
template struct Foo<int>;
template struct Foo<float>;
template struct Foo<double>;
This does not work, as dumpbin.exe on the obj file tells me:
017 00000000 SECT4 notype () External | ?doubleIt@?$Foo@M@@SAMM@Z (public: static float __cdecl Foo<float>::doubleIt(float))
If I change my class definition to define the function outside the class header like so it works correctly:
template <typename T>
struct Foo
{
static T doubleIt(T input);
};
template <typename T>
T Foo::doubleIt(T input)
{
return input * 2;
}
Which we can verify using dumpbin:
017 00000000 UNDEF notype () External | ?doubleIt@?$Foo@M@@SAMM@Z (public: static float __cdecl Foo<float>::doubleIt(float))
The problem with that solution is that it is a lot of typing to move all the function definitions outside of the class definition, especially when you get more template parameters.
I've tried using declspec(__noinline) but it still doesn't extern the functions correctly (and preventing the inlining of the function where possible is undesirable).
One thing that works is to enumerate each function individually, like so, but that of course is even more cumbersome:
extern template int Foo<int>::doubleIt(int);
extern template float Foo<float>::doubleIt(float);
extern template double Foo<double>::doubleIt(double);
What I would like is a way to keep the function definition inside of the class definition, while still allowing the function to be inlined where possible, but when it is not inlined, only creating it in the compilation unit where it is explicitly instantiated (in other words, exactly the same behavior as moving the function outside of the class definition).