Grammar and principles of C++ templates
1. Generic programming
How do I implement a common exchange function?
First method: using function overload to implement
#include<ostream> void swap(int& a, int& b) { int temp = a; a = b; b = temp; } void swap(double& a, double& b) { double temp = a; a = b; b = temp; } int main() { int a = 1, b = 2; swap(a, b); double c = 1.1, d = 2.2; swap(c,d); return 0; }
Second method: using generic programming
Definition: Writing generic type-independent code is a means of code reuse, and templates are the basis of generic programming.
Format: template<typename T1...>{} Return Value Type Function Name Parameter List {} Re-implementation using generic programming swap function
template<typename T> void swap(T& left, T& right) { T temp = left; left = right; right = temp; } int main() { int a = 1, b = 2; swap(a, b); double d1,d2; swap(d1,d2) return 0; }
2. Function templates
**
1. First Identity Function Template
**
Understanding: Function templates represent a family of functions that are type-independent and are parameterized when used to generate corresponding types based on the type of parameters.
Format:
template <typename T1...>{} Return value type function name (parameter list){} A function template is actually a blueprint, not a function in itself, but a stencil for the compiler to use to produce a specific type of function So the function template is actually handing over to the compiler what you were doing.
>In the compilation phase, the compiler deduces a function of the corresponding type based on the type of argument passed in for invocation. As shown above, when the int type uses a function template, the compiler determines T as the int type by deducing the actual parameter type, and then generates a code that specifically handles the int type.
2. Instantiation of function templates
Concepts: When a function template is used with different types of parameters, it is called an instantiation of a function template.
Template parameter instantiation is divided into: implicit instantiation and explicit instantiation
(1) Implicit instantiation: Let the compiler infer the actual type of template parameter based on arguments
template<typename T> T add(const T& left, const T& right) { return left + right; } int main() { int i = 10, j = 20; add(i, j); double a = 10.1, b = 10.2; add(a, b); add(i, a);//This statement cannot be compiled because the compiler cannot make type inferences //Because i is int and a is double, the compiler cannot infer //But there are two ways to deal with this situation: //1. Make a forced conversion, for example: add(i,(int)a); //2. Explicit instantiation return 0; }
(2) Explicit instantiation: specify the actual type of template parameter in <>after the function name
template<typename T> T add(const T& left, const T& right) { return left + right; } int main() { int i = 10, j = 20; add(i, j); double a = 10.1, b = 10.2; add(a, b); //Explicit instantiation: directly specifying the type add<int>(i, j); add<double>(a, b); add<int>(i, a); return 0; }
(3) Principles for matching template parameters: 1. A non-template function can coexist with a function template of the same name, and the function template can also be instantiated as this non-template function.
//Addition functions that deal specifically with int s int add(int left, int right) { return left + right; } //General Addition Function template<typename T> T add(const T& left, const T& right) { return left + right; } int main() { add(1, 2);//Non-template function matching add<int>(1, 2);//Template function matching return 0;
2. For non-template functions and function templates with the same name, if all other conditions are the same, non-template functions will be called first instead of an instance from the template function. If a template can produce a function with a better match, select a template
//Addition functions that deal specifically with int s int add(int left, int right) { return left + right; } //General Addition Function template<typename T> T add(const T& left, const T& right) { return left + right; } int main() { add(1, 2);//Non-template function matching, function template instantiation is not required add(1, 2.0);//Function templates can generate more matching versions, and the compiler generates more matching functions based on arguments. return 0; }
3. Template functions do not allow automatic type conversion, but common functions do.
3. Class Templates
Define format: template <class T1...> class Class Template Name { ...//Intra-class member definition };
(1) Class template instantiation: Class template instantiation is different from function template instantiation. Class template instantiation needs to be followed by <> class template name, and then put the instantiated type in <>. Class template name is not a real class, but the result of instantiation is a real class.
For example: Vector s1; //Instantiate vectors template, int type S1
Vector s2; //Instantiate vectors template, double type S2
template<class T> class Vector { public: Vector(int capacity = 10)//Initialize using an initialization list, constructor , _pData(new T[capacity])//Use new request space and initialization , _size(0) , _capacity(capacity); ~Vector();//Destructors, declared in classes, defined outside classes. T& operator[](int pos) //operator[] overload { assert(pos < _size); return _pData[pos]; } //In addition to reading, you can also modify because of the use of &. private: T* _pData; int _size; int _capacity; }; //The template does not support declaring.h, defining.cpp, and detaching compilation. template <class T> Vector<T> ::~Vector() { if (_pData) { delete[] _pData; } _size = _capacity = 0; }