Since the emergence of OO (object-oriented), with the gradual establishment of the ideological model and the needs of Se development, generic programming has gradually become an important coding method.
The advantage of using generics is that the specific behavior of the source program can be unrelated to the specific type, and the final type is determined to be bound to the final stage. This is a bit like polymorphism in the class.
Templates are the basis of generic programming, and it is hard to imagine what generics without templates will look like.
This article aims to help you understand and understand how to compile your own simple template functions and template classes.
1. What is a template?
In fact, if you do not know much about C ++, it is hard for me to tell you what a template is ......
The meaning of a template in a language is generally "to produce a type of model and apparatus with the same functions", for example, to create a clay sculpture model in a traditional folk work, when you put a pile of mud like shit into a clay sculpture model, and then go through a pile of processes, the specific clay sculpture will eventually come out. The templates in C ++ also play such a role.
If you have used containers in STL, you may have been exposed to containers such as vector, deque, Lis, and map. They are all designed using the template features. The advantage of these containers is that many types of food can be used without the symptoms of indigestion.
2. Why use a template?
This is an interesting and serious issue.
In the era of C, data structure reuse is a headache for programmers. For example, if you write a stack with int as the operation type, therefore, this stack cannot be used to operate Char or double (type conversion is not considered ). If you need to operate other types of stacks, you can only rewrite them once.
Therefore, coder usually uses elementtype to replace the specific type, and then writes typedef int elementtype somewhere in the file using this data structure.
As the saying goes, the first day and the second day are not enough, so a new problem arises. This method cannot take effect for both data types in a single file at the same time.
If you write a stack class in C ++, you can use the template and then use cstack and cstack to define stack objects of different data types.
This advantage is obvious.
3. How to use a template
3.1 Use template Functions
We can use a template for a function separately to make it have the template features. For example, we want to write a swap template function and hope this function can exchange almost all types of two variables.
We can write as follows:
The template definition starts with the keyword template. The template parameters are specified later, indicating that T is the template type.
In some places, the class instead of typename is used here. In fact, they have the same effect. However, the latter is more in line with the template style, and the former exists because many compilers only support class keywords.
After declaring T as a template parameter, you can treat T as a new type, which has the container effect and can accommodate almost all other types.
The benefit of the template type is that the instantiation of the type is determined at the final compilation stage. In the above example, two swaps can be considered as two different functions.
Of course, there can be multiple template parameters, which are valid in both template functions and template classes, but typename must be added before each template type, that is
Template <typename T, typename global>
In addition, the template parameters do not have to be of the template type or built-in type, as long as the compiler determines its type at the time of compilation.
Note that if the template type parameter is used in the return type of the function, it must be specified by the caller, the template type of the returned type must be at the top of the parameter list, because the types of the template parameters are sequentially matched.
- Template <typename rettype, typename input> rettype sum (const input & A, const input & B );
- Int _ tmain (INT argc, _ tchar * argv [])
- {
- Double A = 0.25, B = 1.55;
- Int nret = sum <int> (A, B );
- Wcout <L "the result of 0.25 plus 1.55 is" <nret <Endl; // The result is 1
- _ Getch ();
- Return 0;
- }
- Template <typename rettype, typename input>
- Rettype sum (const input & A, const input & B)
- {
- Return (A + B );
- }
Copy code
3.2 use a template class
In essence, the use of template classes is no different from the use of template functions, but in terms of details, there are still some slight and even confusing issues.
Let's assume we want to write a csort class, which has the functions of Bubble sorting and insert sorting. Of course, this class is a template class, because our sorting type is universal ~
- // In the. h
- Template <typename T>
- Class csort
- {
- Public:
- // Csort ();
- //~ Csort ();
- Void bubblesort (t a [], int ncount );
- Void insertionsort (t a [], int ncount );
- Protected:
- Void swap (T & A, T & B );
- PRIVATE:
- };
- Template <typename T>
- Void csort <t >:: swap (T & A, T & B)
- {
- T TMP =;
- A = B;
- B = TMP;
- }
- Template <typename T>
- Void csort <t >:: bubblesort (t a [], int ncount)
- {
- For (INT n = 1; n <ncount; ++ N)
- {
- Int nupbound = ncount-n-1;
- For (Int J = 0; j <= nupbound; ++ J)
- {
- If (A [J]> A [J + 1])
- {
- Swap (A [J], a [J + 1]);
- }
- }
- }
- }
- Template <typename T>
- Void csort <t>: insertionsort (t a [], int ncount)
- {
- For (INT n = 1; n <ncount; ++ N)
- {
- T ntmp = A [n];
- Int nindex = n-1;
- While (nindex> = 0 & ntmp <A [nindex])
- {
- A [nindex + 1] = A [nindex];
- -- Nindex;
- }
- A [nindex + 1] = ntmp;
- }
- }
Copy code
Here, you may have questions, right! You are not mistaken. The class declaration and implementation are directly in the. h file. What is the reason ~
The class template must first declare the template parameters before the class declaration, and each member function, whether it is a common, private, or protected, must add the declaration of the template parameters before the implementation.
In addition, the template parameter type must be added after the function class name restriction field, such as csort: xx
In the previous example, I commented on the constructor and constructor for a simple reason. If the constructor and constructor are declared, we must implement it, because the template parameters and other things need to be added before the function implementation, and if this is not shown, the compiler will do it by itself. Therefore, this is purely for laziness TVT
As for the use of the template class, as shown in the code below (the header file is omitted ):
- Int _ tmain (INT argc, _ tchar * argv [])
- {
- Int arr [] = {2, 3, 1, 4, 8, 9 };
- Double dbarr [] = {1.2, 2.4, 9.2, 5.7, 3.14, 4.87 };
- Csort <int> intsort;
- Csort <double> dbsort;
- Intsort. bubblesort (ARR, _ countof (ARR ));
- Dbsort. insertionsort (dbarr, _ countof (dbarr ));
- For (INT n = 0; n <= 5; ++ N)
- {
- Wcout <arr [N] <L "/t" <dbarr [N] <Endl;
- }
- _ Getch ();
- Return 0;
- }
Copy code
When using the template class, we need to display the type of the specified class. The csort above is equivalent to the process of binding the template class to the determined type.
If int is specified, the class declaration and template type T in implementation are bound to int.
Template classes with the same binding type can be viewed as one type, such
Csort <int> A, B;
Csort <double> C, D;
Here A and B can be seen as a csort class, while C and D are another csort class.
This plays an important role in understanding the static member variables and functions of the template class.
The preceding figure shows that the static member variables of a class are shared by all class objects, rather than all the class objects. Therefore, they correspond to the template class, it is shared by classes with the same binding type.
Assume that in csort, there is a static variable VAR, so A and B share a var, c and d share another var.
To use the static member function of the template class, you must specify the binding object or directly rely on the object.
Assume that csort has a static function fun, so it should be used as follows:
Csort <char>;
Csort <int>: Fun
Csort <double>: Fun
A: fun;
3.3 how to compile a template class
Since the template type is not a real type, it must wait until the type is bound later to determine the final type. Therefore, you must make the compiler "see" where the template is used, in order to generate the compilation code properly and smoothly.
After talking about this, in fact, in the conventional past, writing class declarations in. h implementations in CPP, and then # inlcude. h won't work. Because CPP is not visible in # inlcude
Therefore, the common solution is to write the implementation directly in. H, which is also the practice of libraries such as STL/wtl.
Er, what are you worried about Inline code expansion? Er, this is indeed a problem. Using wtl, there will indeed be dramatic code expansion, but it does not seem as serious as you think.
The second is to declare and implement the Declaration according to the previous practice, and then change it to # include "XX. cpp" where the inlcude header file is required"
The problem with this is that some compilers do not support it, M $ does not, and g ++ does not. Second, it will lead to repeated compilation, resulting in a significant reduction in compilation performance, so wtl/STL did not adopt this approach.
The third method is the legendary method, that is, adding an export to the class template. This is the best practice, but because it is too idealistic, it can only exist in legends.
In fact, this method is not supported by the compiler yet. When you use export to specify this keyword, the compiler provides the information that has not yet implemented this keyword, but it is retained and will be updated in the future.
So it's a reality. Use the first two methods.