Generic Programming
There are the following codes:
void Swap(int& left, int& right) { int temp = left; left = right; right = temp; }
When we want to call other types of data exchange, we can use function overloading, but 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
In C + +, generic programming: writing generic code independent of type is a means of code reuse. Templates are the foundation of generic programming
The templates are divided into:
- Function template
- Class template
Note: note that the template does not support writing the declaration to. h and defining the way to write to. cpp. A link error will be reported
Function templateconcept
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
The following code:
template<typename T> void Swap( double& left, double& right) { double temp = left; left = right; right = temp; }
Template < typename T > or template < class T > (we think they are the same for the time being here)
When parameters are passed in, the compiler will automatically recognize the type and deduce the function with the correct parameter and return value type with the template
be careful:
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 the function template is used with double type, the compiler determines T as double type through the deduction of argument type, and then generates a code specially dealing with double type, which is the same for character type
Template function instantiation
implicit instantiationThe following are implicit instantiations:
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; Add(a1, a2); Add(d1, d2); }explicit instantiation
When two argument types are different, implicit instantiation is still used, and the compiler will not pass
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; Add(a1, d2); }
The compiler cannot determine whether T should be determined as int or double and an error is reported
Note: in templates, the compiler generally does not perform type conversion
- The first method: Add(a1, (int)d2); (forced transfer type)
- The second method: explicit instantiation
(if the types do not match, the compiler will attempt implicit type conversion. If the conversion fails, the compiler will report an error.)
Add<int>(a, b);
Template function matching
A non template function can exist simultaneously with a template with the same name
// An addition function that deals specifically with int int Add(int left, int right) { return left + right; } // General template addition function template<class T> T Add(T left, T right) { return left + right; } void Test() { Add(1, 2); // The compiler does not need specialization to match non template functions Add<int>(1, 2); // Call the Add version of the compiler specialization }
be careful:
- A function template with the same name can also be instantiated as this 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 (preferred)
- Template functions do not allow automatic type conversion, but ordinary functions can perform automatic type conversion
The format is as follows:
template<class T1, class T2, ..., class Tn> class Class template name { // Intra class member definition };
Example (a Stack class template):
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; } void Push(const T& x); private: T* _a; int _top; int _capacity; };
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
struct TreeNode { // ... }; Stack<TreeNode*> st1; // TreeNode* Stack<int> st2; // int
Note: when the functions in the class template are defined outside the class, the template parameter list needs to be added
template<class T> void Stack<T>::Push(const T& x) { // ... }