Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
You can manually direct the compiler to instantiate any
template specializations of your choice. When you use this technique, there
must be one and only one such directive for each such specialization; otherwise
you might get multiple definition errors, just as you would with
ordinary, non-inline functions with identical signatures. To illustrate, we
first (erroneously) separate the declaration of the min( ) template
from earlier in this chapter from its definition, following the normal pattern
for ordinary, non-inline functions. The following example consists of five
files:
OurMin.h: contains the declaration of the min( )
function template.
OurMin.cpp: contains the definition of the min( )
function template.
UseMin1.cpp: attempts to use an int-instantiation
of min( ).
UseMin2.cpp: attempts to use a double-instantiation
of min( ).
MinMain.cpp: calls usemin1( ) and usemin2( ).
//: C05:OurMin.h
#ifndef OURMIN_H
#define OURMIN_H
// The declaration of min()
template<typename T> const T& min(const
T&, const T&);
#endif //
OURMIN_H ///:~
// OurMin.cpp
#include "OurMin.h"
// The definition of min()
template<typename T> const T& min(const
T& a, const T& b) {
return (a < b) ? a : b;
}
//: C05:UseMin1.cpp {O}
#include <iostream>
#include "OurMin.h"
void usemin1() {
std::cout << min(1,2) <<
std::endl;
} ///:~
//: C05:UseMin2.cpp {O}
#include <iostream>
#include "OurMin.h"
void usemin2() {
std::cout << min(3.1,4.2)
<< std::endl;
} ///:~
//: C05:MinMain.cpp
//{L} UseMin1 UseMin2 MinInstances
void usemin1();
void usemin2();
int main() {
usemin1();
usemin2();
} ///:~
When we attempt to build this program, the linker reports
unresolved external references for min<int>( ) and min<double>( ).
The reason is that when the compiler encounters the calls to specializations of
min( ) in UseMin1 and UseMin2, only the declaration
of min( ) is visible. Since the definition is not available, the
compiler assumes it will come from some other translation unit, and the needed
specializations are thus not instantiated at that point, leaving the linker to eventually
complain that it cannot find them.
To solve this problem, we will introduce a new file, MinInstances.cpp,
that explicitly instantiates the needed specializations of min( ):
//: C05:MinInstances.cpp {O}
#include "OurMin.cpp"
// Explicit Instantiations for int and double
template const int& min<int>(const int&,
const int&);
template const double& min<double>(const
double&,
const double&);
///:~
To manually instantiate a particular template
specialization, you precede the specialization s declaration with the template
keyword. Note that we must include OurMin.cpp, not OurMin.h,
here, because the compiler needs the template definition to perform the
instantiation. This is the only place where we have to do this in this program, however, since
it gives us the unique instantiations of min( ) that we need the declarations
alone suffice for the other files. Since we are including OurMin.cpp
with the macro preprocessor, we add include guards:
//: C05:OurMin.cpp {O}
#ifndef OURMIN_CPP
#define OURMIN_CPP
#include "OurMin.h"
template<typename T> const T& min(const
T& a, const T& b) {
return (a < b) ? a : b;
}
#endif //
OURMIN_CPP ///:~
Now when we compile all the files together into a complete
program, the unique instances of min( ) are found, and the program
executes correctly, giving the output:
You can also manually instantiate classes and static data
members. When explicitly instantiating a class, all member functions for the
requested specialization are instantiated, except any that may have been explicitly
instantiated previously. This is important, as it will render many templates
useless when using this mechanism specifically, templates that implement
different functionality depending on their parameterization type. Implicit
instantiation has the advantage here: only member functions that get called are
instantiated.
Explicit instantiation is intended for large projects where
a hefty chunk of compilation time can be avoided. Whether you use implicit or
explicit instantiation is independent of which template compilation you use. You
can use manual instantiation with either the inclusion model or the separation
model (discussed in the next section).
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |