Summary of C + + template usage (recommended)

Time:2021-6-10

introduction

Template refers to the program design with type as parameter in C + + programming language, which supports general program design. C + + standard library provides many useful functions, most of which combine the concept of template, such as STL and IO stream.

Function template

In the introduction of C + +, many people will contactswap(int&, int&)The code of such a function is as follows:


void swap(int&a , int& b) {
 int temp = a;
 a = b;
 b = temp;
}

However, if we 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, so we can reuse different types of swap function code. 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 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? The instantiation of the template is done by the compiler and has nothing to do with the programmer. Then how to use the above template? The code is as follows:

//main.cpp
#include <stdio.h>
#include "method.h"
int main() {
 //Template method 
 int num1 = 1, num2 = 2;
 swap<int>(num1, num2);
 printf("num1:%d, num2:%d\n", num1, num2); 
 return 0;
}

If you use the swap function here, you must include the definition of swap, otherwise the compilation will be wrong, which is different from the general function. Therefore, it must be added in the last line of the method. H file#include "method.cpp“。

Class template

Consider writing a simple stack class, which can support int type, long type, string type, etc. without using class template, we need to write more than three stack classes, in which the code is basically the same. Through class template, we can define a simple stack template, and then instantiate it as int stack, long stack, 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 definition of a class template stack is very simple, just to illustrate how to use the class template. It can only support up to 100 elements into the stack


//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

Templates can have type parameters, regular type parameters int, and default template parameters, such as

template<class T, T def_val> class Stack{…}

There is a limitation in the stack of the above class template, that is, it can only support 100 elements at most. We can use the template parameters to configure the maximum number of elements in the stack. If not, 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;
}

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 a template, we can use template specialization. For example, if the stack class template we defined is a char * type stack, we hope to copy all the data of char into the stack class, because only the char pointer is saved, the memory pointed by the char pointer may be invalid, and the memory pointed by the stack element char pointer popped up by the stack may be invalid. There is also the swap function template that we defined. In the case of vector or list and other container types, if the objects stored in the container are large, it will take up a lot of memory and degrade the performance, because to generate a temporary large object to save a, all these need the specialization of the template to solve.

Function template specialization

Suppose that our swap function has to deal with a situation where we have two vectors with many elements < int >. When we use the original swap function and execute tmpt = T1, we need to copy all the elements of T1, which takes up a lot of memory and causes performance degradation. Therefore, our system solves this problem through the vector.swap function. The code is as follows:


//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 < > prefix indicates that this is a specialization, and template parameters are not used for description. Examples are as follows:

//main.cpp
#include <stdio.h>
#include <vector>
#include <string>
#include "method.h"
int main() {
 using namespace std;
 //Template method 
 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<int>If you want to use template specialization to solve the swap of all vectors, what should you do? Just add the following code


template<> void swap(std::vector<int>& t1, std::vector<int>& t2) {
 t1.swap(t2);}

Change to


template<class V> void swap(std::vector<V>& t1, std::vector<V>& t2) {
 t1.swap(t2);
}

That’s it. The rest of the code doesn’t change.

Class template specialization

See 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;  // Compare two arguments of type int
 cout << c2.equal(str1, str2) << endl; // Compare two arguments of char * type
 return 0;
 }

When comparing two integers, the equal method of compare is correct, but when the template parameter of compare is char *, the template will not work, so it is modified 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 unchanged, this code can work normally.

Template type conversion

Remember our custom 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 want to use it like this:

It’s impossible here


//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;
}

Compiled becauseStack<Shape*>noStack<Circle*>However, we want the code to work like this. We need to define the conversion operator. The stack code is as follows:


//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 < circle > or stack < circle * > can be automatically converted to stack < Shape > or stack < shape * >. If the conversion type is stack < int > to stack < Shape >, the compiler will report an error.

other

A class has no template parameters, but the member function has template parameters, which 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 equal of util 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;
}

summary

Here is the article about the Usage Summary of C + + template. For more information about the usage of C + + template, please search previous articles of developer or continue to browse the following articles. I hope you can support developer more in the future!