Generic Programming - Getting Started with Templates

Table of contents

function template 

exchange template 

sum of two numbers

call order problem

class template

 Class template declaration and definition separation


 

When implementing multiple types of exchanges, we can use references/pointers to overload functions of multiple types to exchange them, but as a qualified programmer, it is a waste of time to do so. In this article, I will talk about the introductory knowledge of templates and appreciate the charm of C++. 

function template 

//定义模板
template<class T>
template<typename X>
//多参数
template<class M,class N>

 Both methods can define a template, and the template name is self-selected and generally uppercase. 

exchange template 

Through debugging, enter the body of the Swap function using the template every time, and exchange the int and double types.

There is a problem here, are we calling the same function?

of course not.

The reason why a template is called a template is because it is a mold , and the essence is to call other overloaded functions separately . Every time the function is called, go back to deduce and instantiate the function of the corresponding type. The principle: let the compiler do the work .

Digression: Why can't auto be used?

Because auto can only be derived at the compile stage, and the function call is determined at the runtime stage, so you cannot use auto

Disassembly observation:

 The c++ library provides a swap function template, which we can also use to swap in the future.

sum of two numbers

Let's implement a template using the sum of two numbers to observe the problems that arise with different types of sums.

template<class X>
X Add(const X& a, const X& b)
{
	return a + b;
}

 It can be found that different types of parameters are passed, which leads to ambiguity in the derivation of the template (if the int type is deduced but another type is not recognized as int), there is a problem. Below we provide two ways to solve it.

Implicit is easy to understand, and explicit writing is to convert them into int types by specifying the type to be deduced by the template. Note that both of these methods generate temporary variables here, and the function needs to be modified with const .

Although both can solve the problem, try not to add different types to avoid problems such as loss of precision.

call order problem

There is such a scenario, if we have written a type of addition function and its template, which one will the compiler call.

Call the template operation explicitly :

Add<int>(a, b);//<int,int>调用单参
Add<int>(a,c);//<int,double>调用双参,无双参模板报错
Add<int>(c,a);//c强转为int,<int,int>调用单参
Add<int,double>(a,b);//显式调用双参
Add<int,int>(a,b);//显式调双参

Templates support overloading 

 It can be seen that the compiler is very smart. The addition of the int type we wrote will be called first , so that there is no need to instantiate the corresponding function. The second time the compiler chooses the second one of the two templates, which also shows that The compiler will call the closest matching template.

class template

For example, we want to implement a stack. I use typedef to define a stack that stores the int type internally. After that, each of our objects can only store the int type, and cannot store the double type. If we create another class, we have to implement a lot of repetitions by ourselves. code, this is definitely not going to work. For this, it is necessary to write classes with templates.

Rewrite the stack class:

template <class M>
class Vector
{
public:
	Vector(int capaicty = 4)
	{
		_a = new M[capaicty];//
		_top = 0;
		_capacity = capaicty;
	}
	M& operator[](int pos)
	{
		assert(pos < _top);
		return _a[pos];
	}
    void pushback(const M& x);
	~Vector()
	{
		delete[] _a;//开辟的是数组空间
        _a = nullptr;
		_capacity = _top = 0;
	}

private:
	M* _a;//
	size_t _top;
	size_t _capacity;
};

 The compiler generates different types of stacks

Vector <int> s1;
Vector <double> s2;

Different from function templates, class template instantiation needs to be followed by <> , and the data type is in the brackets. The compiler calls different classes according to the corresponding type to form a complete class type . (The class name of a common class is the class name + type ) The Vector here is the name of the class template obtained by ourselves.

 Class template declaration and definition separation

Note that the separation of declaration and definition of class templates is a bit different. They can only be placed in the same file , otherwise link errors will occur .

Let's take ~Vector as an example:

~Vector();//声明
template <class M>//定义
Vector<M>:: ~Vector()
{
	delete[] _a;
	_a = nullptr;
	_capacity = _top = 0;
}

Note here that the definition must follow the definition of the template  on the first line and <M> must be added after Vector to form a complete type. It is generally not recommended to separate the declaration and definition.

This is the basic content of the initial template, and then we will talk about advanced templates, don't forget to click three times! 

Guess you like

Origin blog.csdn.net/dwededewde/article/details/130783624