1. Generic programming
For example, how to realize the general function of exchanging 2 numbers?
void Swap(int x, int y) { int tmp = x; x = y; y = tmp; } void Swap(double x, double y) { int tmp = x; x = y; y = tmp; }
Although function overloading can be implemented, there are several disadvantages:
- Overloaded functions only have different types, and the reuse rate of code is relatively low. As long as new types appear, corresponding functions need to be added
- The maintainability of the code is relatively low. An error may occur in all overloads
Can you tell the compiler a model and let the compiler use the model to generate code according to different types?
2. Function template
2.1 concept of function template
Function template is actually a general-purpose function. Its function type and formal parameter type are not specified. It is represented by a virtual type. This general-purpose function is called function template.
2.2 form of function template
template<typename T1, typename T2,...,typename Tn>
Return value type function name (parameter list) {}
Or replace typename with class (class cannot be replaced with struct)
//Function template template<typename T> void Swap( T& left, T& right) { T temp = left; left = right; right = temp; }
2.3 principle of function template
Function template is a blueprint. It is not a function itself. It is a mold for the compiler to generate specific types of functions by using. So in fact, the template is to give the compiler the repeated things we should have done.
Let's mask the following code
//void Swap(int x, int y) //{ // int tmp = x; // x = y; // y = tmp; //} //void Swap(double x, double y) //{ // int tmp = x; // x = y; // y = tmp; //}
The exchange has been successfully completed here.
2.4 function template instantiation
When a function template is used with different types of parameters, it is called instantiation of the function template. Template parameter instantiation can be divided into implicit instantiation and explicit instantiation.
- Implicit instantiation: let the compiler deduce the actual type of template parameters according to the actual parameters
template<class T> T Add(const T& left, const T& right) { return left + right; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; //2 of the same type Add(a1, a2); Add(d1, d2); cout << Add(a1, a2) << endl; cout << Add(d1, d2) << endl; return 0; }
There is no problem with the above code. When we give, for example:
//An int, a double
Add(a1, d1);
Deduce T as int through argument a1 and double through argument d1, but there is only one T in the template parameter list,
The compiler cannot determine whether T should be determined as int or double and an error is reported
Note: in the template, the compiler generally does not perform type conversion, because once there is a problem with conversion, the compiler needs to bear the blame
//Force type conversion to make the same type Add(a1,(int)d1); Add((double)a1, d1);
2. Explicit instantiation: specify the actual type of template parameter in < > after the function name
Add<int>(a1,d1); Add<double>(a1, d1);
2.5 matching principle of template parameters
- A non template function can exist simultaneously with a function template with the same name, and the function template can also be instantiated as the non template function
-
- For non template functions and function templates with the same name, if other conditions are the same, the non template function will be called first during transfer, and an instance will not be generated from the template. If the template can produce a function with a better match, the template will be selected
- For non template functions and function templates with the same name, if other conditions are the same, the non template function will be called first during transfer, and an instance will not be generated from the template. If the template can produce a function with a better match, the template will be selected
3. Class template
Form of type 3.1 formwork
template<class T1, class T2, ..., class Tn>
class template name
{
//Intra class member definition
};
3.2 instantiation of class template
Class template instantiation is different from function template instantiation. Class template instantiation needs to follow the class template name with < >, and then put the instantiated type in < >. The class template name is not a real class, but the instantiation result is a real class.
// Class template // Ordinary class, the class name is the type // Class template, class name is not type, type is stack < T > template<class T> class Stack { public: Stack(int capacity = 4) :_a(new T[capacity]) , _top(0) , _capacity(capacity) {} ~Stack() { delete[] _a; _a = nullptr; _top = _capacity = 0; } // What about the declaration inside the class and the definition outside the class void Push(const T& x); private: T* _a; int _top; int _capacity; }; //Define outside of class template<class T> void Stack<T>::Push(const T& x) { // ... }
The above is the initial stage of the template!