解决办法详见下文..
Templates do not exist! (there is no spoon)
•Templates are a preprocessor construct. They are cookie-cutters with which the preprocessor generates real C++ code. When a template is used, (that is, specialized, implicitly or explicitly), it getinstantiated.
•The instantiation tells the preprocessor to create a version of the template where each placeholder is replaced by its specialization. At this point, the specific version of the template comes into existence and can be compiled. It does not exist otherwise!
•In a very real way, a template just does a search and replace for each type you specialize the template for. In essence, you are doing the same as writing a bunch of overloaded functions. It’s just done for you, behind your back.
Here, the template has been implicitly specialized by its context. It is within the specialization region of the class scope. Thus it does not need the template arguments. For a class definition, the specialization region is the class block.
Notice that the specialization
region does not include the return type. Thus the return type needs explicit specialization.
Remember that though constructors and destructors have the same name as the class template, they are functions and do not need to be specialized.
Problem
Templates do not exist until you use them. They must be instantiated. Unless this is done explicitly, instantiation occurs at the first usage for all known template definitions. Thus, consider this example. Compile with
g++ -Wall –ansi main.cc Matrix.cc
#include < iostream >
using namespace std;
#include “Matrix.h”
int main( void ) {
Matrix<int> m1(3,4);
cout << m1.getRows() << endl;
}
Looks innocent, but it won’t link
Quiz: What won’t link and why?
The link error happens with m1.getRows()
•Nothing from a template gets instantiated until it is either used or explicitly instantiated. • Matrix<int>::getRows() const does not get created until it is used at the line with m1.getRows(). The definition of the function is in Matrix.cc and never used there. Thus the definition never gets created and compiled to object code.
Note: The compile line is actually wrong!
The file Matrix.cc only contains template code. Since it is never used, it never generates object code and shouldn’t be compiled.
************************************************
There are three conventions to avoiding the link problem
•Write all the code inline in the .h files.
•Do the same as above, but kind of fake it by writing an implementation file with your implementation and #include the implementation file in your header file.
•Write the template as you would a normal class (using a header and an implementation file). Then create a new source file and #include the template implementation file there. This is the file which you compile, not the template implementation. (See next slide for example)
The first two methods have the problem that anytime an implementation of a function is changed, all code that uses it must be recompiled (not just relinked). This is very slow on large builds. Also, the build process will instantiate the template many more times than necessary which is a waste of time and space. The third method is free from such problems. It also avoids some other hurdles since it forces the instantiation of everything at one point.
compile line:
g++ –Wall –ansi main.cc MatrixInst.cc
#include < iostream >
using namespace std;
#include < Matrix.h >
int main( void ) {
Matrix<int> m1(3,4);
cout << m1.getRows() << endl;
}
#include “Matrix.cc”
template Matrix < int >
// notice that the implementation (not header) file is included
The proper procedure
•Write the template, separated into a header and an implementation file
•Create an instantiation file for the template which include the implementation file.
•Compile the instantiation file and not the template implementation file.
•The instantiation file generates the object code for the template.