First paste the code, this is C + + Primer 4th edition Exercise 16.17
First, the Declaration and definition of the template are separate
<span style= "FONT-SIZE:18PX;" >//median.h#ifndef __median_h__#define __median_h__#include <vector> #include <algorithm>using Namespace::std;template <typename T>bool Median (const vector<t>&, t&);//#include "median.cpp" # Endif</span>
<span style= "FONT-SIZE:18PX;" >//median.cpp#include "Median.h" #include <vector> #include <iostream>using namespace::std;template <typename T>bool Median (const vector<t>& VEC, t& middle) {vector<t> temp (VEC); if (Temp.size () % 2 = = 0) return False;sort (Temp.begin (), Temp.end ()), typename Vector<t>::size_type index = temp.size ()/2;if ( (Temp[index] > Temp[index-1]) && (Temp[index] < Temp[index + 1]) {middle = Temp[index];return true;} Elsereturn false;} </span>
Next is the simple test case
<span style= "FONT-SIZE:18PX;" > #include "median.h" #include <vector> #include <iostream>using namespace::std;int main () { int ia1[ ] = {1, 2, 3, 4, 5, 6, 7}; int ia2[] = {1, 2, 3, 4}; int ia3[] = {1, 2, 3, 4, 5, 6}; Vector<int> ivec1 (Ia1, ia1+7); Vector<int> ivec2 (IA2, ia2+4); Vector<int> ivec3 (IA3, ia3+6); int m; if (median (IVEC1, m)) cout << "median:" << m << endl;elsecout << "No median" << endl;if (median (IVEC2, M)) cout << "median:" << m << endl;elsecout << "No median" << endl;if (Median (IVEC3, m)) cout < < "median:" << m << endl;elsecout << "No median" << Endl;return 0;} </span>
Let's talk about the problem first.
1, if the header file does not add # include "Median.cpp", the program run error.
The reason for the analysis should be that the template written on C++primer is different from the normal function, when instantiated, the compiler must be able to access the source code that defines the template, where the source code is not found, so the display is undefined.
2, if the header file added # include "Median.cpp", the program run error.
The reason for the analysis is that the above header file contains the Cpp,cpp and also contains the header file, and then displays the duplicate definition.
Why is there a second kind of error? After checking the data to understand, the process of compiling the program.
First of all, analyze the basic process of common function compiling links:
The main content of http://blog.csdn.net/bichenggui/article/details/4207084 in the detailed introduction, I only for the part of the analysis.
Generating exe files from source code takes two steps, compiles and links.
1. During compilation, a compilation unit (translation unit) refers to a. cpp file and its # All the. h files in the include, the code in the. h file will be extended to the. cpp file containing it, and the compiler compiles the. cpp file as an. obj file, and it contains the binary code itself.
2. During the linking process, the compiler compiles all the. cpp files in a project in a separate way, and then the connector (linker) connects to an. exe file.
Learn from an example:
<span style= "FONT-SIZE:18PX;" >//---------------Test.h-------------------//void f ();//Declare a function here f//---------------test.cpp--------------//# Include "test.h" void f () { ...//do something}// This implements the F function declared in Test.h//---------------main.cpp--------------//# Include "Test.h" int main () { f ();//call F,f with external connection type}</span>
compile phase: Test. cpp and main.cpp are each compiled into different. obj files (named Test.obj and Main.obj), and the F function is called in main.cpp, but when the compiler compiles main.cpp, it Just know a declaration of Void F () in the Test.h file contained in main.cpp, so the compiler considers f here as an external connection type . That is to say that its function implementation code in another. obj file, this example is test.obj, that is, Main.obj does not actually have a single line of binary code about the F function, and the code actually exists in the test.obj compiled by Test.cpp.
Link stage: The call to F in Main.obj will only generate a single row of calls, which is obviously wrong at compile time, because there is no implementation code for a line F in main.obj. What about that? This is the task of the connector, which is responsible for finding the implementation code of F in the other. obj (in this case, test.obj), and finding the function entry point address of the call F, which is the calling address of the instruction, to the actual F. It is important to note that the connector actually "connects" the. obj in the project into an. exe file, and its most critical task is to look for an external connection symbol in another. obj address, and then replace the original "false" address
With content from the original
Call F This line of command is actually not the case, it is actually called stub, that is, a jmp 0xABCDEF. This address may be arbitrary, but the key is that there is a single line of instructions on the address to perform the real call F action. In other words, all calls to F in this. obj file are in jmp to the same address, where it is really "call" F. The advantage of this is that the connector modifies the address as long as it changes the call XXX address of the latter. However, how does the connector find the actual address of F (in this case this is in test.obj) because. obj is the same format as the. exe, in which there is a symbol import table and a Symbol export table (import table and exported Table) where all the symbols are associated with their addresses. So the connector simply looks for the address of the symbol f (c + + f mangling) in the Test.obj's symbolic export table, Then do some offset processing (because the two. obj files are merged, of course the address will have a certain offset, this connector is clear) to write to the symbol in the Main.obj table in the form of the one that the F occupies.
In simple terms:
1, compile test.cpp, the compiler found the implementation of F, so the implementation of F (binary code) appears in the Test.obj.
2, compile main.cpp, The compiler does not know the implementation of F, so when the call to it just give an indication, indicating that the connector should look for it to find the implementation of F. This means that there is no line of main.obj on F for any binary code
3. When linking, the linker finds the address of F's implementation code (binary) in Test.obj, and then changes the unresolved call XXX address in main.obj to the actual address of F.
Next, analysis of the function template compilation process, the main feature is that the C + + standard is clear that when a template is not used, it should not be instantiated .
"Main.cpp" need to drop the template function, but in the included header file does not have the implementation of the function, so during the compilation process, also did not generate the corresponding binary code, can only hope that in the link process can be found in other. obj in the corresponding function of the instance, but in the " Median.cpp "median (const vector<t>& VEC, t& middle), is not instantiated, simply because there is no binary code in the compilation generated MEDIAN.O. Therefore, in the last link process can not find the definition of the function, only error.
In view of the above problems, found on the Internet, in order to avoid this situation, can only talk about function declarations and function definitions, class declarations and class definitions, written in the same file, called the. hpp file, so call the template can see the implementation of the source code, do not appear the above situation.
To add: HPP, in essence, is to mix the implementation code of. CPP into the. h header file, where the definition and implementation are contained in the same file, the caller of the class only needs to include the HPP file, eliminating the need to add CPP to project for compilation. The implementation code is compiled directly into the caller's obj file, and no separate obj is generated, and HPP will drastically reduce the number of CPP files and compile times in project, as well as the annoying Lib and DLL releases, making it ideal for writing common open source libraries.
Do not know what better way to solve this problem, hope to see friends, can give a suggestion.
Analysis of C + + template declaration and definition compilation process