[C + +] template (function template) (class template) (generic programming)

Posted by Pascal P. on Sun, 06 Mar 2022 11:11:35 +0100


Hello, bald men. Let's talk about the template today

Key points of this chapter

  1. Generic Programming
  2. Function template
  3. Class template

Generic Programming

How do we usually exchange two numbers? Obviously, we'll write a swap function

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}
void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}

Obviously, function overloading can be implemented, but there are some disadvantages:

  1. Overloaded functions only have different types, and the reuse rate of code is relatively low. As long as new types appear, corresponding functions need to be added
  2. The maintainability of the code is relatively low. An error may occur in all overloads

Can you tell the compiler a model and let the compiler use the model to generate corresponding code according to different types?

If such a mold can exist in C + +, it will save a lot of hair by filling the mold with different materials (types) to obtain castings of different materials (generate specific types of codes).

The above is generic programming

Generic programming: writing generic code independent of type is a means of code reuse. Templates are the foundation of generic programming

Function 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.
The function template itself is not a function, but a mold. The compiler generates the corresponding function according to the different types of parameters we pass in.

Function template format

template<typename T1, typename T2,......,typename Tn>
Return value type function name(parameter list){}

be careful:
typename is a keyword used to define template parameters. You can also use class (remember: struct cannot be used instead of class)

template<class T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}

Principle of function template

In short, the principle is very simple, that is, we use a mold, we pass different parameters to it, and the compiler generates the corresponding type of code for us.

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 template functions, 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 double type, the compiler determines T as double type through the deduction of the argument type, and then generates a code specially dealing with double type, which is the same for character type.

Instantiation of function template

When a function template is used with different types of parameters, it is called instantiation of the function template. Template parameter instantiation can be divided into implicit instantiation and explicit instantiation.

  1. Implicit instantiation: let the compiler deduce the actual type of template parameters according to the actual parameters
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	Add(a1, a2);
	Add(d1, d2);
	
	//Add(a1,d2);// This is not allowed and ambiguous
	// At this time, there are two processing methods: 1 Users themselves to force conversion 2 Use explicit instantiation
	Add(a, (int)d);
	return 0;
}
  1. Parameter name after instantiation: specified in actual template
int main()
{
	int a = 10;
	double b = 20.0;
	// explicit instantiation 
	Add<int>(a, b);
	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

  1. 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 left, int right)
{
	return left + right;
}
// General addition function
template<class T>
T Add(T left, T right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // The compiler does not need specialization to match non template functions
	Add<int>(1, 2); // Call the Add version of the compiler specialization
}
  1. 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 during transfer, and an instance will not be generated from the template. If the template can produce a function with a better match, the template will be selected
// An addition function that deals specifically with int
int Add(int left, int right)
{
	return left + right;
}
// General addition function
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // It exactly matches the non function template type and does not require function template instantiation
	Add(1, 2.0); // The template function can generate a more matching version, and the compiler generates a more matching Add function according to the arguments
	//But the type of return depends on whether you are T1 or T2
}
  1. Template functions do not allow automatic type conversion, but ordinary functions can perform automatic type conversion

Class template

Definition format of class template

template<class T1, class T2, ..., class Tn>
class Class template name
{
// Intra class member definition
};
// 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)
	{}
	// Demonstration using destructors: declared in a class and defined outside the class.
	~Vector();
	void PushBack(const T& data);
		void PopBack();
		// ...
		size_t Size() { return _size; }
	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

Class template instantiation is different from function template instantiation. Class template instantiation needs to be followed by < >, and then put the instantiated type in < >. The class template name is not a real class, but the instantiation result is a real class.

Template < template parameter list declaration > < class declaration >, and the member functions of the class template are template functions

// Vector class name, vector < int > is the type
Vector<int> s1;
Vector<double> s2;

Class template is a class family, and template class is a concrete class instantiated through class template.

To sum up:
1. The most important point of the template is that it is type independent, which improves the reusability of the code
2. When the template runs, it does not check the data type and does not guarantee the type safety. It is equivalent to the macro replacement of type
3. As long as the syntax of the template is supported, the code of the template is portable
4. The use of templates is typical of generic programming

⭐ Thanks for reading. I'll see you next time
If there is any mistake, welcome to communicate with us

Topics: C++ Back-end