[C++] template template

 

Table of contents

1. Function template

1.1 Function template concept

1.2 Function Template Format

1.3 Principle of function template

1.4 Instantiation of function templates

1.4.1 Implicit instantiation

1.4.2 Explicit instantiation

1.5 Matching principle of template parameters

2. Class template

2.1 Definition format of class template

2.2 Instantiation of class templates


Before we talk about templates, let's talk about generic programming:

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.
There are two types of templates: function templates and class templates

1. Function template

1.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.

1.2 Function Template Format

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

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

Note: typename is used to define template parameter keywords, and class can also be used (remember: struct cannot be used instead of class).

1.3 Principle of function template

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.

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, and the same is true for the character type.

1.4 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.4.1 Implicit instantiation

Implicit instantiation is to let the compiler deduce the actual type of the template parameter based on the actual parameter

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);
    
    return 0;
}

Here Add(a1, a2) and Add(d1, d2) are both implicit instantiations, and the compiler will deduce the actual type according to the actual parameters.

Let's look at another piece of code:

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
	int i = 1;
	double d = 1.1;
	Add(i, d);

	return 0;
}

This statement cannot be compiled, because during compilation, when the compiler sees the instantiation, it needs to deduce its parameter type. T is deduced as an int by the actual parameter i, and T is deduced as a double type by the actual parameter d, but the template parameter There is only one T in the list, and the compiler cannot determine whether T should be of type int or double and reports an error.

Note: In the template, the compiler generally does not perform type conversion operations, because once there is a problem with the conversion, the compiler needs to take the blame Add(i, d);

There are two ways to solve this problem here:

1. User to force conversion;

2. Use explicit instantiation.

int main()
{
	int i = 1;
	double d = 1.1;
	Add(i, (int)d);

	return 0;
}

1.4.2 Explicit instantiation

Explicit instantiation is to specify the actual type of the template parameter in <> after the function name

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int i = 1;
	double d = 1.1;
	Add<int>(i, d);// 显式实例化为int
	Add<double>(i, d);// 显示实例化为double

	return 0;
}

If the types do not match, the compiler will try to perform an implicit type conversion, and if the conversion fails, the compiler will report an error.

1.5 Matching principle of template parameters

1. 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

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

2. 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 preferentially 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

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
	Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数 
}

3. Template functions do not allow automatic type conversion, but ordinary functions can perform automatic type conversion

2. Class template

2.1 Definition format of class template

template<class T1, class T2, ..., class Tn>
class 类模板名
{
	// 类内成员定义
};
template<class T>
class stack
{
public:
	stack();//声明,在类外面定义

	~stack()
	{
		delete[] _a;
		_top = _capacity = 0;
	}
private:
	T* _a;
	int _top;
	int _capacity;
};

// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template<class T>
stack<T>::stack()
	: _a(nullptr)
	, _top(0)
	, _capacity(0)
{}

2.2 Instantiation of class templates

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 .

int main()
{
	stack<int> st1;
	stack<char> st2;

	return 0;
}

If our stack is to store data of type int, we instantiate it as int, and if it stores data of type char, it instantiates it as type char.

Guess you like

Origin blog.csdn.net/Ljy_cx_21_4_3/article/details/132282805