A friend who has written a template may know that a template program does not generate code immediately when the compiler sees the template definition. Only when we use the template and instantiate it, to generate a specific instance. At this point, the compiler will access the source code of the definition template. If the source code is not accessible, the compiler reports an error. I remember that when I was a beginner, I used to directly put all the statements and implementations in A. H. However, sometimes we really want to declare in the. h file that is implemented in the CPP file to implement file separation. Next I will write general template functions, template classes, and special template file separation, my own experience.
In C ++ primer, two models of C ++ compiling template code are described: (1) including compiling (2) Compiling separately
(1) include compilation model: you can add a # include instruction to the header file of the declared function template or class template to make the definition available, so as to introduce the source file containing the relevant definition.
// header file utlities.h#ifndef UTLITIES_H#define UTLITIES_Htemplate <class T> int compare(const T&, const T&);......#include "utilities.cpp"#endif
//implementation file utlities.cpptemplate <class T> int compare(const T &v1,const T &v2){ //implemente ......}
This policy separates header files from source files.
(2) separate compilation: in the separate compilation mode, the declaration of the function template is placed in the header file. In this mode, the function template declaration and definition organization method are the same as the non-inline function declaration and definition organization method in the program. Compiling models separately only uses the keyword "Export" to tell the compiler where the template definition is referenced.
If export is used in the header file class declaration, the header file can only be used once by the source file; If export is used in the implementation file, there are two usage methods:
Export class
// XXXXX. the H file defines the class template <typename type> class test {/*... * //}; // In XXXXX. export template <typename type> class test; # include "XXXXX. H "... // implementation class member <
Export class member functions. Only use export for members respectively.
// XXXXX. in the H file, only template <typename type> type max (Type T1, Type T2) is declared; // In XXXXX. in the CPP file, // The template defines the export template <typename type> type max (Type T1, Type T2 ){/*... */}
You may feel so easy to see. Okay, so you go home and knock on the code, and you will find that your compiler vs may tell you wrong!
First, let us know that part of the reason is the compiler problem. vs does not support separate compilation. That is to say, if you compile the code according to the above compilation policies, the compiler will tell you that we do not currently provide support for the keyword export, and may provide support in the future. In addition, different versions of VC support different standard templates of C ++, for example, vc6.0 does not support some special templates...
Then you may adopt the first type of include compilation, which is supported by all compilers, but you will find that there are still errors. Let's look at the following code:
In the header file
#ifndef tmp_h#define tmp_h#include <iostream>#include<vector>using namespace std;template<typename T> class Worker{public:typename vector<T>::size_type sz;T test(const T& t1);};#include "tmp.cpp"#endif
In the CPP File
# Include "tmp. H "template <typename ch> void display (string Str); // This function is implemented in other files, template <typename T> T Worker <t>: Test (const T & T1) {string STR = "worker: test is running! ";: Display <char> (STR); Return T1 ;}
And then call
void main(){ Worker<int> w1; w1.test(12.0); _getch();}
The above code satisfies the C ++ primer policy, but the compiler reports an error:
Error c2995: 'tworker <t >:: test (const T &) ': function template has already been defined
This is because the header file contains the corresponding CPP file, but if multiple files contain this header file, the CPP file will also be compiled multiple times. So the above errors have occurred. To prevent the preceding errors caused by inclusion compilation, modify the CPP file as follows:
#ifndef tmp_cpp#define tmp_cpp#include"tmp.h"template<typename ch>void Display(string str);template<typename T>T Worker<T>::test(const T& t1){string str = "worker::test is Running!";::Display<char>(str);return t1;}#endif
CPP files also use pre-compiled commands to prevent repeated compilation. This solves the problem.
Maybe you thought it was the end. Compilation seems to be completely solved. However, in another case, if our template function contains a special version of the template, the compiler still reports an error. Let's look at the following code:
// In func. H, we declare several template functions (using the policy described above)
# Ifndef func_h # define func_h # include <iostream> # include <vector> # include <iterator> # include <algorithm> using namespace STD; template <typename ch> void display (string Str); Template <typename type> void work (Type T1); Template <> void Work <int> (INT T1 ); // special version of work # include "func. CPP "# endif
// Implement func. cpp as follows
#ifndef FUNC_CPP#define FUNC_CPP#include "func.h"template<typename ch>void Display(string str){ostream_iterator<char>out_it(cout, "");copy(str.begin(), str.end(), out_it);*out_it = '\n';};template<typename Type>void Work(Type t1){string txt = "Work func nomal is runing !";Display<char>(txt);}template<typename Type,int Num>Type Sum(const Type& t1, int Num){string txt = "The sum of t1+Num is: ";Type tp = t1+Num;Display<char>(txt);cout<<tp<<endl;return tp;}template<>void Work<int>( int t1){string txt = "now Work is special version.";Display<char>(txt);}#endif
In another CPP File
Void main () {typedef void (* ptem) (double T1); // defines a pointer to call a non-specific template function ptem = work; ptem (3232.0 ); work <int> (323) // call the template function of the special version}
It seems that there is no problem, but you still report an error after compiling. No?
Error lnk2005: "Void _ cdecl Work <int> (INT )"(?? $ Work @ H @ yaxh @ Z) already defined in func. OBJ
It's also a redefinition !! We have used the # ifndef pre-compilation command. Why is it redefined when the target file is generated. In addition, it only means that the special version is redefined. The specific reason is the compilation mechanism of the special version. I don't want to talk about it here, because the mechanism is complicated. I can't make a shift here if I don't fully understand it. So here we will only talk about my two solutions:
1. the inclusion compilation method is still used, which is the simplest. You only need to declare the function of the special version as the inline function (other functions remain unchanged ).
// Template <> inline void Work <int> (INT T1) in the header file; // template <> inline void Work <int> (INT T1) in the CPP File) {string TXT = "now work is special version. "; display <char> (txt );}
Remember to add inline here!
2. Discard include compilation and use the previous stupid method to put all the implementation of basic template functions in the header file, and only declare the special version of functions in the header file. Only functions of the specific version are implemented in the CPP file.
# Ifndef func_h # define func_h # include <iostream> # include <vector> # include <iterator> # include <algorithm> using namespace STD; /// // The basic template function is implemented in the header file ///////// ////// // template <typename ch> void display (string Str) {ostream_iterator <char> out_it (cout, ""); copy (Str. begin (), str. end (), out_it); * out_it = '\ n';}; Template <typename type> void work (Type T1) {string TXT = "Work func nomal is runing ! "; Display <char> (txt);} template <> void Work <int> (INT T1 ); // statement of the special version # endif // only functions of the specific version are implemented in the file /// /// // # include "func. H "# ifndef func_cpp # define func_cpptemplate <> void Work <int> (INT T1) {string TXT =" now work is special version. "; display <char> (txt) ;}# endif
This can also be compiled. Maybe you think the second method is not brilliant. The first method is recommended if you do not like it.
To sum up, I personally think that it is very easy and convenient to compile the template program. (Compile separately for the moment, because not every compiler supports this method .) However, you should pay attention to some special cases, such as the example above.