C++ Template

黄舟
Release: 2016-12-13 14:31:07
Original
1349 people have browsed it

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;
}
Copy after login

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;
Copy after login

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"
Copy after login
//method.cpp

template<typename  T> void swap(T& t1, T& t2) {
    T tmpT;
    tmpT = t1;
    t1 = t2;
    t2 = tmpT;
}
Copy after login

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;
}
Copy after login

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"
Copy after login
//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;
}
Copy after login

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;
}
Copy after login

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{...}
Copy after login

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"
Copy after login
//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;
}
Copy after login

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;
}
Copy after login

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. Using the original swap function, execute tmpT = t1 needs to copy all the elements of t1, which takes up a lot of memory and causes performance degradation. So 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"
Copy after login
#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);
}
Copy after login

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;
}
Copy after login

vector is still relatively limited. If you want to use template specialization to solve the swap of all vectors, how to do it? You only need to change the following code

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

to

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

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;
  }
};
Copy after login
#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;
 }
Copy after login

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;
    }
};
Copy after login

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 {
};
Copy after login


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;
}
Copy after login
Copy after login

This cannot be compiled because Stack is not the parent class of Stack. However, we want the code to work like this, so we have 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"
Copy after login
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;
}
Copy after login
//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;
}
Copy after login
Copy after login

In this way, Stack or Stack can be automatically converted to Stack or Stack. If the converted type is Stack to Stack, the compiler will report an error .

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;
}
Copy after login

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;
}
Copy after login


Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!