It seems to be a common convention not to use source files for template based classes (STL and boost) and to put the implementation into the header as well. I assume that this will increase the time it takes to compile the source files that include the header drastically compared to the classic separation between declaration and implementation in header and source files. The reason why this is done is probably due to the fact that you would have to tell the compiler in the source file which templates to use, which will probably result in a bloated .a file.
Assuming the linker also requires more time as the library grows, which approach would be faster in terms of the time it takes to compile a source file that includes the library header?
1. Not using a .cpp file and put the entire class, including the implementation, into the header
//foo.hpp
template <class T>
class Foo
{
public:
Foo(){};
T bar()
{
T* t = NULL;
//do stuff
return *t;
}
};
or
2. Explicitly compiling the template for various types inside the source file of the library itself
//foo.h
template <class T>
class Foo
{
public:
Foo(){};
T bar();
};
//foo.cpp
template <class T>
T Foo<T>::bar()
{
T* t = NULL;
//do stuff
return *t;
}
template class Foo<int>;
template class Foo<float>;
template class Foo<double>;
template class Foo<long long>;
The key issue with templates is that the compiler won't know for which template arguments a template will be used. The only time the compiler knows a template is used with a specific set of arguments is when it sees the template used and the compiler will instantiate the template at this point. As a result the code is often put into the header so the compiler can instantiate the template on the user's behalf when it is used.
Alternatively, the author of a template can tell the compiler that a template is used with a specific list of template arguments and just instantiate them explicitly. In this case, the template definition can go into a source file (or, more likely, a special header not generally included by users). The problem with this approach is that the author of the template code doesn't necessarily know which instantiations are needed.
In C++ 2011 there is also a middle ground: It is possible to tell the compiler that certain instantiations are already created by declaring a specialization as extern
. This way, the compiler knows that it doesn't need to instantiate the template with certain arguments but if other arguments are used it knows that it needs to create them. For example, the standard C++ library has std::basic_string
and it can predict that instantiations for char
and wchar_t
are likely to be used and can put them into the library, declaring the instantiations as extern
. However, having the code readily available makes it viable to use std::basic_string<user_type>
with user defined types.
Going forward we hope to get a module system but right now nobody really knows how such a system should really work. The compiler implementers who are interested in the topic have a group to think about modules and it is likely that a system like this may help with compile times for templates.