Initial stage of formwork
Generic Programming
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?
If such a mold can exist in C + +, it will save a lot of hair by filling the mold with different materials (types) to obtain castings of different materials (generate specific types of codes). Coincidentally, our predecessors have already planted trees, so we just need to enjoy the cool here.
Generic programming: writing generic code independent of type is a means of code reuse. Templates are the foundation of generic programming.
Function template
Function template concept
The function template represents a function family. The function template is independent of type and is parameterized when used. The specific type version of the function is generated according to the argument type.
Function template format
template<typename T1, typename T2,...,typename Tn>
Return value type function name (parameter list) {}
//Function template template<class T> void Swap(T& x1, T& x2) { T tmp = x1; x1 = x2; x2 = tmp; } int main() { int a = 10, b = 20; double c = 4.2, d = 6.3; printf("a = %d,b = %d", a, b); printf("c = %.2f,d = %.2f\n", c, d); Swap(a, b); Swap(c, d); printf("a = %d,b = %d", a, b); printf("c = %.2f,d = %.2f\n", c, d); return 0; }
Note: typename is a keyword used to define template parameters, and class can also be used (remember: struct cannot be used instead of class)
Principle of function template
Let's first see if the Swap function above calls the same function and how to verify it
Function template is a blueprint. It is not a function itself. It is a mold that the compiler uses to generate specific types of functions. So in fact, the template is to give the compiler the repeated things we should have done
In the compiler compilation stage, for the use of template functions, the compiler needs to deduce and generate functions of corresponding types according to the input argument types for calling. For example, when using the function template with double type, the compiler determines T as double type through the deduction of the argument type, and then generates a code specially dealing with double type, which is the same for character type.
Instantiation of function template
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
1. Implicit instantiation: let the compiler deduce the actual type of template parameters according to the actual parameters
2. Explicit instantiation: specify the actual type of template parameter in < > after the function name
template <class T> T Add(const T& x,const T& y) { return x + y; } int main() { int a = 2, b = 6; double c = 3.5, d = 5.6; //Do not let the compiler deduce types //Explicit Instantiation cout<< Add<int>(a, c)<<endl; cout << Add<double>(b, d) << endl; return 0; }
Matching principle of template parameters
1. A non template function can exist simultaneously with a function template with the same name, and the function template can also be instantiated as this non template function
2. 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
Through the gif above, we can see the non template function and a function template with the same name. We are advanced non template functions. If not, we will enter the function instantiated by the compiler template
3. Template functions do not allow automatic type conversion, but ordinary functions can perform automatic type conversion
Class template
//Class template //We used to define a sequence table. How do we define it typedef int VDataType; class vector //The order table defined in cpp is vector, which means vector { public: // private: VDataType* _a; int _size; int _capacity; }; int main() { vector v1; //v1 save int vector v2; //v2 save double return 0; }
//Class template template <class T> class vector //The order table defined in cpp is vector, which means vector { public: // private: T* _a; int _size; int _capacity; }; int main() { vector<int> v1; //v1 save int vector<double> v2; //v2 save double return 0; }
Definition format of class template
template<class T1, class T2, ..., class Tn> class Class template name { // Intra class member definition }; // Dynamic sequence table // Note: Vector is not a concrete class, but a mold for the compiler to generate a concrete class according to the instantiated type template<class T> class Vector { public: Vector(size_t capacity = 10) : _pData(new T[capacity]) , _size(0) , _capacity(capacity) {} // Demonstration using destructors: declared in a class and defined outside the class. ~Vector(); void PushBack(const T& data); void PopBack(); // ... size_t Size() { return _size; } T& operator[](size_t pos) { assert(pos < _size); return _pData[pos]; } private: T* _pData; size_t _size; size_t _capacity; }; // Note: when the functions in the class template are defined outside the class, the template parameter list needs to be added template <class T> Vector<T>::~Vector() { if (_pData) delete[] _pData; _size = _capacity = 0; }
Instantiation of class template
Class template instantiation is different from function template instantiation. Class template instantiation needs to be followed by < >, and then put the instantiated type in < >. The class template name is not a real class, but the instantiation result is a real class.
// Vector class name, vector < int > is the type Vector<int> s1; Vector<double> s2;