[C ++ template programming]-function template

In our previous programming ideas, every function we wrote was of a data type.
For example, the compare function, we write a function for the int data type, and we write an identical function for the double type. Think about whether this is very troublesome, so we introduced the template in C ++.

The meaning of the template is to parameterize the type.

1. Function template

1. Related concepts

For the above-mentioned compare function, we template it and write a function template as follows:

template<typename T>
bool compare(T a, T b)
{
	cout << "template compare" << endl;
	return a > b;
}

For the above code, we have a few terms to explain.

( 1) Template type parameters : The
template implementation is to define a template parameter list (which contains two template type parameters, which can also be used in class, but it is easy to cause misunderstandings, generally not used, all used typename)

(2) Function template :
compare is a template of a function, and defines two formal parameter variables with the T type without compiling

In the main function, we can use the function template like this

int main()
{
	compare<int>(10, 20);
	compare<double>(10.1, 20.1);
	compare(10, 20);

(3) The template function
is instantiated at the call point as written in the main function tree. The template function he generated is as follows, which is to be compiled with a compiler:

template<typename int>
bool compare(int a, int b)
{
	cout << "template compare" << endl;
	return a > b;
}

At the function call point, the compiler instantiates a function code from the original template with the user-specified type
template function. The code is not reduced from the compiler, but the code is indeed reduced from the user's perspective

(4) The deduction of the actual parameters of the template :
just like the third sentence call written in the main function tree, there is no parameter type of the given template. But because of the argument deduction of the function template. Only need to call the first instantiated function here

Further, if we want to achieve string comparison, we write as follows:

compare("aaa","bbb");

The deduced type is const char *. But this is comparing the address size of two strings, in fact, the string manipulation function strcmp should be called

For the compare function template, a specialized version of the const char * type is provided, implemented as follows:

template<>
bool compare<const char*>(const char* a, const char* b)
{
	cout << "compare<const char*>" << endl;
	return strcmp(a, b) > 0;
}

For some types, depending on the template code instantiated by the compiler by default, the code processing logic is wrong.
So we introduce the concept of specialization (specialization) of templates.

(5) Specialization of templates:
For some types, the code processing logic is wrong depending on the template code instantiated by the compiler by default. Not provided by the compiler, but provided by the user.

You can also write a normal function directly to call

bool compare(const char* a, const char* b)
{
	cout << "normal compare" << endl;
	return strcmp(a, b) > 0;
}

The compiler first treats compare as a function name, if not, it will go to the compare template

2. Rules for writing function templates

Because the function template is not compiled, the template code cannot be used in one file to define another file. Before calling the template code, be sure to look at the place where the large template is defined, so that the template can be instantiated normally and generated by the compiler Code, so the template code is placed in the header file, #include contains in the source file

3. Non-type parameters of the template

Must be of integer type (integer or address / reference can be) are constants, can only be used, can not be modified.
For example, in the following example, the size of the array needs to be passed in when using bubble sorting. The specific implementation is as follows:

template<typename T,int SIZE>
void sort(T* arr)
{
	for (int i = 0; i < SIZE - 1; ++i)
	{
		for (int j = 0; j < SIZE - 1 - i; ++j)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}
int main()
{
	int arr[] = { 12,5,7,89,32,21,35 };
	const int size = sizeof(arr) / sizeof(arr[0]);
	sort<int,size>(arr);
	for (int val : arr)
	{
		cout << val << " ";
	}
	cout << endl;
}

At the call point of the function, the non-type parameter SIZE of the template should be passed in

Second, the class template

When explaining the class template, in order to explain more visually, we simulate the implementation of the sequence stack

template<typename T>
class SeqStack
{
public:
	SeqStack(int size = 10)
		:_pstack(new T[size])
		,_top(0)
		,_size(size)
	{}
	~SeqStack()
	{
		delete[] _pstack;
		_pstack = nullptr;
	}
	SeqStack(const SeqStack<T>& stack)
		:_top(stack._top)
		,_size(stack._size)
	{
		_pstack = new T[_size];
		//不要用memcopy进行拷贝(做的是浅拷贝)
		for (int i = 0; i < _top; ++i)
		{
			_pstack[i] = stack._pstack[i];
		}
	}
	SeqStack<T>& operator = (const SeqStack<T>& stack)
	{
		if (this == &stack)
			return *this;

		delete[] _pstack;

		_top = stack._top;
		_size = stack._size;
		_pstack = new T[_size];
		for (int i = 0; i < _top; ++i)
		{
			_pstack[i] = stack._pstack[i];
		}
		return *this;
	}

	void push(const T& val)
	{
		if (full())
			expand();
		_pstack[_top++] = val;
	}
	void pop()
	{
		if (empty())
			return;
		--_top;
	}
	T top()const
	{
		if (empty())
			throw "stack is empty!";//抛异常也代表函数逻辑结束
		return _pstack[_top - 1];
	}
	bool full()const { return _top == _size; }
	bool empty()const { return _top == 0; }


private:
	T* _pstack;
	int _top;
	int _size;

	//顺序栈底层数组按2倍的方式扩容
	void expand()
	{
		T* ptmp = new T[_size * 2];
		for (int i = 0; i < _top; ++i)
		{
			ptmp[i] = _pstack[i];
		}
		delete[]_pstack;
		_pstack = ptmp;
		_size *= 2;
	}
};
int main()
{
	SeqStack<int> s1;
	s1.push(20);
	s1.push(89);
	s1.push(21);
	s1.push(12);
	s1.pop();
	return 0;
}

note!
(1) SeqStack behind class is called the template name , not the class name. Template name + type parameter list = class name

(2) The name of the constructor and destructor does not need to be added , and the type parameter list is added wherever the template appears

(3) Selective instantiation of class templates: which method does the template class use after our class template is instantiated?

Published 98 original articles · won praise 9 · views 3671

Guess you like

Origin blog.csdn.net/qq_43412060/article/details/105102861