Detailed explanation of C++ templates (function templates, class templates)

hello, this is bangbang, let's talk about templates today

Table of contents

1. Generic programming

2. Function templates

  2.1 Function template concept

  2.2 Function Template Format

  2.3 Instantiation of function templates

  2.4 Matching principle of template parameters

3. Class Templates

  3.1 Class template definition format

  3.2 Class template instantiation

4. Non-type template parameters

5. Template specialization

  5.1 Template specialization concept

  5.2 Function template specialization

  5.3 Class template specialization

6. Template separate compilation

  6.1 What is separate compilation

  6.2 Separate compilation of templates

7. Summary


1. Generic programming

How to implement a generic swap function?

Some friends may think of overloading with functions, as follows:

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

But there is a problem here, as long as my type does not conform to the function parameter, then I have to overload another copy, which is too troublesome!

1. The overloaded functions are only of different types, and the code reuse rate is relatively low. As long as a new type appears, the user needs to add the corresponding function
2. The maintainability of the code is relatively low, one error may cause all overloads to be error

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

Generic programming: Writing generic code that has nothing to do with types is a means of code reuse. Templates are the foundation of generic programming .

2. Function templates

  2.1 Function template concept

        A function template represents a family of functions. The function template has nothing to do with the type. It is parameterized when used, and a specific type version of the function is generated according to the type of the actual parameter.
        A function template is a blueprint. It is not a function itself, but a mold for the compiler to generate a specific type of function by using it. So in fact, the template is to hand over the repetitive things that we should have done to the compiler.

  2.2 Function Template Format

template<typename T1, typename T2,......,typename Tn>
返回值 函数名(参数列表)
{}
Note: typename is used to define template parameter keywords , and class can also be used ( remember: struct cannot be used instead of class)

The function template of the exchange function (the two parameter types are the same):

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

        In the compiler compilation stage , for the use of template functions, the compiler needs to deduce and generate corresponding types of functions for calling according to the type of actual parameters passed in . For example: when using a function template with a double type, the compiler determines T as a double type through the deduction of the actual parameter type, and then generates a code that specifically handles the double type

  2.3 Instantiation of function templates

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

        1. Implicit instantiation: let the compiler deduce the actual type of the template parameter according to the actual parameter

Function templates (assuming 1 template parameter), what happens if there is a type mismatch?

We all know that C++ built-in types perform calculations and perform upward arithmetic conversions , such as int+double=double, so how does the function template handle this, or directly convert the structure into a double? Let's see:

At this point, there are two ways to deal with it: 1. The user forces the conversion by himself. 2. Use display instantiation.

User casts himself:

Add(a1,(int)d1);

        2. Display instantiation: specify the actual type of the template parameter in <> after the function name

Add<int>(a1,d1);//显示实例化

  2.4 Matching principle of template parameters

  • A non-template function can coexist with a function template with the same name, and the function template can also be instantiated as this non-template function
Under VS, press F11 at the break point to view and find that only Add<int>() enters the function template
  • For a non-template function and a function template with the same name, if other conditions are the same, the non-template function will be called first and an instance will not be generated from the template when mobilizing. If the template can produce a function with a better match, then the template will be chosen

  • Template functions do not allow automatic type conversion, but ordinary functions can do automatic type conversion

3. Class Templates

  3.1 Class template definition format

template<class T1, class T2, ..., class Tn>
class 类模板名
{
 // 类内成员定义
};

 Note: When a function in a class template is defined outside the class, a template parameter list needs to be added

//类模板
template<class T>
class Vector
{}

//类外定义
template<class T>
Vector<T>::函数定义

  3.2 Class template instantiation

Class template instantiation is different from function template instantiation. Class template instantiation needs to follow the class template name with <>, and then put the instantiated type in <> . The class template name is not a real class, but the instantiated The result is the real class .
//Vector类名,Vector<int>类型
Vector<int> v;

4. Non-type template parameters

Classification of template parameters: type parameters participate in non-type parameters .
Type parameter: Appears in the template parameter list, followed by the parameter type name such as class or typename.
Non-type parameter: It is to use a constant as a parameter of the class (function) template, and the parameter can be used as a constant in the class (function) template.
namespace lh
{
	// 定义一个模板类型的静态数组
	template<class T, size_t N = 10>
	class array
	{
	public:
		T& operator[](size_t index) { return _array[index]; }
		const T& operator[](size_t index)const { return _array[index]; }

		size_t size()const { return _size; }
		bool empty()const { return 0 == _size; }

	private:
		T _array[N];
		size_t _size;
	};
}
Notice:
1. Floating point numbers, class objects, and strings are not allowed as non-type template parameters.
2. Non-type template parameters must be able to confirm the result at compile time.

Let’s add array here. Let’s think about writing code in normal times. The array uses C++ array or C array form. Why does C++ have to create an array class?

 Now that the boss has done it, it must be different from C! I don’t know if my friends usually find that the array form of C language is very loose for out-of-bounds checks!

 

 Advantage:

 In the C language, the out-of-bounds check adopts the spot check method ( pointer dereferencing ), no error is reported for out-of-bounds reading, and limited error is reported for out-of-bounds writing.

 C++11, as long as the array is out of bounds, it will be found ( function call ).


5. Template specialization

  5.1 Template specialization concept

Usually, templates can be used to implement some type-independent codes, but for some special types, some wrong results may be obtained, which require special handling, for example: implement a function template specially used for less than comparison
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
     return left < right;
}
int main()
{
     cout << Less(1, 2) << endl; // 可以比较,结果正确
     Date d1(2022, 7, 7);
     Date d2(2022, 7, 8);
     cout << Less(d1, d2) << endl; // 可以比较,结果正确
     Date* p1 = &d1;
     Date* p2 = &d2;
     cout << Less(p1, p2) << endl; // 可以比较,结果错误
     return 0;
}
It can be seen that Less can be compared normally in most cases, but wrong results are obtained in special scenarios. In the above example, the d1 pointed to by p1 is obviously smaller than the d2 object pointed to by p2, but Less does not compare the contents of the objects pointed to by p1 and p2 internally, but compares the addresses of p1 and p2 pointers , which cannot meet expectations and is wrong.
At this point, the template needs to be specialized. That is: on the basis of the original template class, it is a specialized implementation method for a special type . Template specialization is divided into function template specialization and class template specialization .

  5.2 Function template specialization

The specialization steps of a function template:
  1. There must be a basic function template first
  2. The keyword template is followed by a pair of empty angle brackets <>
  3. The function name is followed by a pair of angle brackets, which specify the type to be specialized
  4. Function parameter table: It must be exactly the same as the basic parameter type of the template function. If it is different, the compiler may report some strange errors.
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
	return left < right;
}
// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
	return *left < *right;
}
void date_test()
{
	cout << Less(1, 2) << endl;
	Date d1(2022, 7, 7);
	Date d2(2022, 7, 8);
	cout << Less(d1, d2) << endl;
	Date* p1 = &d1;
	Date* p2 = &d2;
	cout << Less(p1, p2) << endl; // 调用特化之后的版本,而不走模板生成了
}
Note: In general, if the function template encounters a type that cannot be processed or is processed incorrectly, the function is usually given directly for simplicity of implementation .
bool Less(Date* left, Date* right)
{
     return *left < *right;
}
This kind of implementation is simple and clear, the code is highly readable, and easy to write, because for some function templates with complex parameter types, specialization is given during specialization, so specialization is not recommended for function templates .

  5.3 Class template specialization

Full specialization: determinizes all parameters in the template parameter list.
Partial specialization: partial specialization (for pointer type/for reference type/pointer, reference composite type)

typename also tells the compiler whether this is a type or a variable!

Because static type variables can also access specified class fields, when using types, we add typename in front to distinguish them. ( Without the compiler, it is not clear whether it is a type or a variable )


6. Template separate compilation

  6.1 What is separate compilation

        A program (project) is jointly implemented by several source files, and each source file is compiled separately to generate an object file, and finally the process of linking all object files to form a single executable file is called separate compilation mode.
        Templates do not support separate compilation!

  6.2 Separate compilation of templates

 Link problem: there are declarations that cannot find the definition

7. Summary

advantage:

        1. The template reuses the code, saves resources, and enables faster iterative development, which is why the C++ Standard Template Library (STL) comes into being. (Repeated work is handed over to the compiler)

        2. Enhanced the flexibility of the code.

shortcoming:

        1. Templates can lead to code expansion problems and longer compilation times.

        2. When a template compilation error occurs, the error message is very messy and it is not easy to locate the error.


Guess you like

Origin blog.csdn.net/bang___bang_/article/details/130653863