When learning C language, we all wrote a function called swap, which is used to exchange the values of two variables. Like this.
void Swap(int& left, int& right){ int temp = left; left = right; right = temp; } void Swap(double& num1, double& num2){ int tmp = num1; num1 = num2; num2 = tmp; } ...
We found that if we want to exchange two variables of type int, we need a function whose parameter is two ints. If we want to exchange two variables of type double, we need to write a Swap function to implement two variables of type double. This will be very troublesome, so c + + has the concept of a 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>
template<typename T1, typename T2 ... typename Tn>
template<class T1>
template<class T1, class T2, ... class Tn
Return value type function name (parameter list) {}
All of the above are OK
template<typename T> void swap(T& num1, T& num2){ T tmp = num1; num1 = num2; num2 = tmp; } int main(){ int i1 = 10; int i2 = 20; Swap(i1, i2); double d1 = 2.0; double d2 = 5.0; Swap(d1, d2); return 0; }
ps: typename is a keyword used to define template parameters. You can also use class
Principle of function template
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 function templates, 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 the double type, the compiler determines T as the double type through the deduction of the argument type, and then generates a code specially dealing with the double type
Instantiation of function template
Using function templates with different types of parameters to automatically generate corresponding functions is called instantiation of function templates. Function template instantiation is divided into implicit instantiation and display instantiation
Implicit instantiation: let the compiler deduce the actual type of template parameters according to the actual parameters
#include<iostream> using namespace std; template<class T> T Add(const T& num1, const T& num2){ return num1 + num2; } int main(){ int a1 = 10, a2 = 20; double d1 = 2.1, d2 = 3.1; cout << Add(a1, a2) << endl; cout << Add(d1, d2) << endl; Add(a1, d1); // Can this statement be compiled Add(a1, (int)d1); // Can this statement be compiled? }
Display instantiation: specify the actual type of template parameter after the function name
int main(){ int a =10; int d = 2.1; // Explicit Instantiation Add<int>(a, b); // Specifies that T is of type int return 0; }
If the types do not match, the compiler will attempt implicit type conversion. If the conversion fails, the compiler will report an error
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
// An addition function that deals specifically with int int Add(int num1, int num2){ return num1 + nim2; } // General addition function template<class T> T Add(T num1, T num2){ return num1 + num2; } int main(){ Add(1, 2); // The compiler does not need to instantiate to match non template functions Add<int>(1, 2); // Call the Add version instantiated by the compiler return 0; }
-
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 when calling, and an instance will not be generated from the template. If the template can produce a function with better matching, the template will be selected
// An addition function that deals specifically with int int Add(int num1, int num2){ return num1 + num2; } // General addition function template<class T1, class T2> T1 Add(T1 num1, T2 num1){ return num1 + num2; } int main(){ Add(1, 2); // It exactly matches the non function template type and does not require function template instantiation Add(1, 3.2); // Function templates can produce more matching versions return 0; }
Class template
Definition format of class template
template<class T1, class T2, ... ,class Tn > class Class template name { // Class member definition };
Before designing a dynamic sequence table, if we want to design an int sequence table and a char sequence table, we need to implement them separately. With a class template, we can write a template to let the compiler automatically identify the data type and generate the corresponding class.
// 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) {} // Use the destructor demonstration to declare in the class and define outside the class ~Vector(); void PushBack(const T& data); void PopBack(); //... 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 int main(){ Vector<int> s1; Vector<char> s2; return 0; }
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