1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
Up to now, we've only defined template functions. There are various
hi(template functions: multiply included)
consequences of including template function definitions in multiple source
files, none of them serious, but worth knowing.
itemization(
it() Like class interfaces, template definitions are usually included in
header files. Every time a header file containing a template definition is
read by the compiler, the compiler must process the definition in full, even
though it might not actually need the template. This will relatively slow-down
the compilation. For example, compiling a template header file like
tt(algorithm) on my old laptop takes about four times the amount of time it
takes to compile a plain header file like tt(cmath). The header file
tt(iostream) is even harder to process, requiring almost 15 times the amount
of time it takes to process tt(cmath). Clearly, processing templates is
serious business for the compiler.
it() Every time a template function is instantiated, its code appears in
the resulting object module. However, if multiple instantiations of a
template, using the same actual types for its template parameter exist in
multiple object files, then the linker will weed out superfluous
instantiations. In the final program only one instantiation for a particular
set of actual template type parameters will be used (see also section
ref(TEMPFUNINST) for an illustration). Therefore, the linker will have an
additional task to perform (em(viz.) weeding out multiple instantiations),
which will slow down the linking process.
it() Sometimes the definitions themselves are not required, but only
references or pointers to the templates are required. Requiring the compiler
to process the full template definitions in those cases will unnecessarily
slow down the compilation process.
)
Instead of including template definitions again and again in various
source files, templates may also be declared. When templates are declared, the
compiler will not have to process the template's definitions again and again,
and no instantiations will be created on the basis of template declarations
alone. Any actually required instantiation must, as holding true for
declarations in general, be available elsewhere. Unlike the situation we
encounter with concrete functions, which are usually stored in libraries, it
is currently not possible to store templates in libraries (although
precompiled header files may be implemented in various
compilers). Consequently, using template declarations puts a burden on the
shoulders of the software engineer, who has to make sure that the required
instantiations exist. Below a simple way to accomplish that is introduced.
A template function declaration is simply created: the function's body is
replaced by a semicolon. Note that this is exactly identical to the way
concrete function declarations are constructed. So, the previously defined
template function tt(add()) can simply be declared as
verb(
template <typename Type>
Type add(Type const &lvalue, Type const &rvalue);
)
Actually, we've already encountered i(template declarations). The header
file tt(iosfwd) may be included in sources not requiring instantiations
hi(#include <iosfwd>)
of elements from the class ti(ios) and its derived classes. For example,
in order to compile the em(declaration)
centt(std::string getCsvline(std::istream &in, char const *delim);)
it is not necessary to include the tt(string) and tt(istream) header
files. Rather, a single
centt(#include <iosfwd>)
is sufficient, requiring about one-ninth the amount of time it takes to
compile the declaration when tt(string) and tt(istream) are included.
|