Function template
In getting started with C++, many people will come into contact with swap(int&, The similar code for a function like int&) is as follows:
void swap(int&a , int& b) { int temp = a; a = b; b = temp; }
But if you want to support the swap function of long, string, and custom class, the code is similar to the above code, but the type is different. At this time, we define the function template of swap. To reuse different types of swap function codes, the declaration form of the function template is as follows:
template <class identifier> function_declaration; template <typename identifier> function_declaration;
The declaration and definition code of the swap function template is as follows:
//method.h template<typename T> void swap(T& t1, T& t2); #include "method.cpp"
//method.cpp template<typename T> void swap(T& t1, T& t2) { T tmpT; tmpT = t1; t1 = t2; t2 = tmpT; }
The above is the declaration and definition of the template. How to instantiate the template? Instantiation is something done by the compiler and has nothing to do with programmers. So how to use the above template? The code is as follows:
//main.cpp #include <stdio.h> #include "method.h" int main() { //模板方法 int num1 = 1, num2 = 2; swap<int>(num1, num2); printf("num1:%d, num2:%d\n", num1, num2); return 0; }
The swap function is used here, and the definition of swap must be included, otherwise the compilation will error. This is different from the general function use. Same. So #include must be added to the last line of the method.h file "method.cpp".
Class Template
Consider we write a simple stack class. This stack can support int type, long type, string type, etc. Without using class templates, we have to write more than three stack classes, in which the code is basically Similarly, through class templates, we can define a simple stack template and instantiate it as an int stack, long stack, or string stack as needed.
//statck.h template <class T> class Stack { public: Stack(); ~Stack(); void push(T t); T pop(); bool isEmpty(); private: T *m_pT; int m_maxSize; int m_size; }; #include "stack.cpp"
//stack.cpp template <class T> Stack<T>::Stack(){ m_maxSize = 100; m_size = 0; m_pT = new T[m_maxSize]; } template <class T> Stack<T>::~Stack() { delete [] m_pT ; } template <class T> void Stack<T>::push(T t) { m_size++; m_pT[m_size - 1] = t; } template <class T> T Stack<T>::pop() { T t = m_pT[m_size - 1]; m_size--; return t; } template <class T> bool Stack<T>::isEmpty() { return m_size == 0; }
The above defines a class template - stack. This stack is very simple. It is just to illustrate how to use the class template. It can only support up to 100 elements on the stack. The usage example is as follows:
//main.cpp #include <stdio.h> #include "stack.h" int main() { Stack<int> intStack; intStack.push(1); intStack.push(2); intStack.push(3); while (!intStack.isEmpty()) { printf("num:%d\n", intStack.pop()); } return 0; }
Template parameters
The template can have Type parameters can also have regular type parameters int, or default template parameters, such as
template<class T, T def_val> class Stack{...}
The stack of the above class template has a limitation, that is, it can only support a maximum of 100 elements. We can use template parameters to configure this stack The maximum number of elements. If not configured, set the default maximum value to 100. The code is as follows:
//statck.h template <class T,int maxsize = 100> class Stack { public: Stack(); ~Stack(); void push(T t); T pop(); bool isEmpty(); private: T *m_pT; int m_maxSize; int m_size; }; #include "stack.cpp"
//stack.cpp template <class T,int maxsize> Stack<T, maxsize>::Stack(){ m_maxSize = maxsize; m_size = 0; m_pT = new T[m_maxSize]; } template <class T,int maxsize> Stack<T, maxsize>::~Stack() { delete [] m_pT ; } template <class T,int maxsize> void Stack<T, maxsize>::push(T t) { m_size++; m_pT[m_size - 1] = t; } template <class T,int maxsize> T Stack<T, maxsize>::pop() { T t = m_pT[m_size - 1]; m_size--; return t; } template <class T,int maxsize> bool Stack<T, maxsize>::isEmpty() { return m_size == 0; }
Usage examples are as follows:
//main.cpp #include <stdio.h> #include "stack.h" int main() { int maxsize = 1024; Stack<int,1024> intStack; for (int i = 0; i < maxsize; i++) { intStack.push(i); } while (!intStack.isEmpty()) { printf("num:%d\n", intStack.pop()); } return 0; }
Template specialization
When we want to define different implementations of templates, we can use template specialization . For example, the stack class template we defined, if it is a char* type stack, we hope to copy all the data of char to the stack class, because only the char pointer is saved, and the memory pointed to by the char pointer may become invalid, and the stack element popped up by the stack The memory pointed to by the char pointer may be invalid. There is also the swap function template we defined. When using container types such as vector or list, if the object saved by the container is large, it will occupy a lot of memory and reduce performance, because a temporary large object needs to be generated to save a, which requires a template. Specialization can solve it.
Function template specialization
Suppose our swap function wants to handle a situation. We have two vectors with many elements
//method.h template<class T> void swap(T& t1, T& t2); #include "method.cpp"
#include <vector> using namespace std; template<class T> void swap(T& t1, T& t2) { T tmpT; tmpT = t1; t1 = t2; t2 = tmpT; } template<> void swap(std::vector<int>& t1, std::vector<int>& t2) { t1.swap(t2); }
template<> The prefix indicates that this is a specialization and no template is used when describing it. Parameters, usage examples are as follows: The swap code of
//main.cpp #include <stdio.h> #include <vector> #include <string> #include "method.h" int main() { using namespace std; //模板方法 string str1 = "1", str2 = "2"; swap(str1, str2); printf("str1:%s, str2:%s\n", str1.c_str(), str2.c_str()); vector<int> v1, v2; v1.push_back(1); v2.push_back(2); swap(v1, v2); for (int i = 0; i < v1.size(); i++) { printf("v1[%d]:%d\n", i, v1[i]); } for (int i = 0; i < v2.size(); i++) { printf("v2[%d]:%d\n", i, v2[i]); } return 0; }
vector
template<> void swap(std::vector<int>& t1, std::vector<int>& t2) { t1.swap(t2); }
to
template<class V> void swap(std::vector<V>& t1, std::vector<V>& t2) { t1.swap(t2); }
That’s it, other codes remain unchanged.
Class template specialization
Please look at the compare code below:
//compare.h template <class T> class compare { public: bool equal(T t1, T t2) { return t1 == t2; } };
#include <iostream> #include "compare.h" int main() { using namespace std; char str1[] = "Hello"; char str2[] = "Hello"; compare<int> c1; compare<char *> c2; cout << c1.equal(1, 1) << endl; //比较两个int类型的参数 cout << c2.equal(str1, str2) << endl; //比较两个char *类型的参数 return 0; }
When comparing two integers, the equal method of compare is correct, but when the template parameter of compare is char*, the template cannot work, so I modified it. As follows:
//compare.h #include <string.h> template <class T> class compare { public: bool equal(T t1, T t2) { return t1 == t2; } }; template<>class compare<char *> { public: bool equal(char* t1, char* t2) { return strcmp(t1, t2) == 0; } };
main.cpp file remains unchanged and this code can work normally.
Template type conversion
Do you still remember our customized Stack template? In our program, suppose we define the Shape and Circle classes, the code is as follows:
//shape.h class Shape { }; class Circle : public Shape { };
Then we hope to use it like this:
//main.cpp #include <stdio.h> #include "stack.h" #include "shape.h" int main() { Stack<Circle*> pcircleStack; Stack<Shape*> pshapeStack; pcircleStack.push(new Circle); pshapeStack = pcircleStack; return 0; }
This cannot be compiled because Stack
//statck.h template <class T> class Stack { public: Stack(); ~Stack(); void push(T t); T pop(); bool isEmpty(); template<class T2> operator Stack<T2>(); private: T *m_pT; int m_maxSize; int m_size; }; #include "stack.cpp"
template <class T> Stack<T>::Stack(){ m_maxSize = 100; m_size = 0; m_pT = new T[m_maxSize]; } template <class T> Stack<T>::~Stack() { delete [] m_pT ; } template <class T> void Stack<T>::push(T t) { m_size++; m_pT[m_size - 1] = t; } template <class T> T Stack<T>::pop() { T t = m_pT[m_size - 1]; m_size--; return t; } template <class T> bool Stack<T>::isEmpty() { return m_size == 0; } template <class T> template <class T2> Stack<T>::operator Stack<T2>() { Stack<T2> StackT2; for (int i = 0; i < m_size; i++) { StackT2.push((T2)m_pT[m_size - 1]); } return StackT2; }
//main.cpp #include <stdio.h> #include "stack.h" #include "shape.h" int main() { Stack<Circle*> pcircleStack; Stack<Shape*> pshapeStack; pcircleStack.push(new Circle); pshapeStack = pcircleStack; return 0; }
In this way, Stack
Others
A class has no template parameters, but the member function has template parameters. It is feasible. The code is as follows:
class Util { public: template <class T> bool equal(T t1, T t2) { return t1 == t2; } }; int main() { Util util; int a = 1, b = 2; util.equal<int>(1, 2); return 0; }
You can even declare Util's equal as static, the code is as follows:
class Util { public: template <class T> static bool equal(T t1, T t2) { return t1 == t2; } }; int main() { int a = 1, b = 2; Util::equal<int>(1, 2); return 0; }