Reputation: 56479
Writing template classes we have to inline the method bodies usually in .h
files (unless instantiating them in .cpp
files).
We know modifying an inlined method requires recompiling the units which included them. It'll make compiling long.
Another technique to implement a template class is instantiating it in a .cpp
file.
File Test.h
:
template <typename T>
class Test
{
public:
T data;
void func();
};
File Test.cpp
:
template <typename T>
void Test<T>::func()
{
}
template class Test<float>; // explicit instantiation
Well. Is this technique effective to reduce compilation time for who uses Test<float>
after any modification on func()
?
Upvotes: 4
Views: 1182
Reputation: 208323
Since the definitions of the member functions are all inside the cpp and thus not available to other translation units, the functions won't be implicitly instantiated and thus the cost of compiling the code is limited to the single cpp.
The problem with that approach is that you are limiting the use of your template to the type (or types) for which you provide the manual instantiations. External users cannot instantiate it for other types, if you have to do it, you need to remember to manually specialize for each type you want to use.
There is an alternative, with slightly more cost (not much), but that is generic and faster to compile than the naïve approach. You can provide the template definitions in the header, but instruct the compiler not to implicitly instantiate it for a set of common types, then provide manual instantiations for it in a single translation unit:
// .h
#ifndef TEST_H
#define TEST_H
template <typename T>
class Test
{
public:
T data;
void func() { ... } // definition here
};
extern template class Test<float>; // Declare explicit instantiation for float
extern template class Test<int>; // for int
#endif /* TEST_H */
// cpp
#include "test.h"
template class Test<float>; // explicit instantiation
template class Test<int>;
In this approach the template is visible for instantiations with any type that the user might want to use. But you explicitly tell the compiler not to do the work for a known subset of types for which you provide the specializations. If the user wants Test<std::string>
then the compiler will instantiate it implicitly, and that translation unit will pay the price. For translation units that only instantiate Test<float>
, Test<int>
or that include the header but don't instantiate the template at all, there will be some additional cost (the parser needs to handle the definitions) but there won't be generated code (binary), or time wasted on the optimizer and/or the linker discarding duplicate symbols.
It also implies, as you mention, recompiling all user code that included that header if the contents of the header change.
Upvotes: 3