Advanced C + + template

Non type template parameters

Template parameter classification type shape participates in non type parameter.
Type parameter: it appears in the template parameter list, followed by parameter type names such as class or typename.
A non type parameter is to use a constant as a parameter of the class (function) template, which can be used as a constant in the class (function) template.

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
// Define a static array of template types
//T is a type template parameter
//N is a non type template parameter and N is a constant
template<class T=char, 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;
};
int main()
{
	Array<int, 100> a1;
	Array<double> a2;
	Array<> a3;
	return 0;
}

Note:
All template parameters can be given default values
The default values given to template parameters are completely similar to the default values given to function parameters (full default and semi default (continuous default must be from right to left))
Floating point numbers, class objects, and strings are not allowed as non type template parameters.
Non type template parameters must be able to confirm the results at compile time.

Summary:

  • It is not recommended to use array in STL. It is better to use vector, because if the amount of data is large, it may lead to stack overflow
  • Forword in STL_ List does not provide tail insertion and tail deletion because the efficiency is too low
  • array and forword in STL_ List is very chicken ribs, often make complaints about it.
  • One of the disadvantages of C + + is that the late C++11 and other standards have added a lot of chicken rib syntax, which makes the language bloated and increases the learning cost. There are some just needed things that are late or even haven't come yet (Network Library)

Specialization of template

Function template specialization (less used)

Specialization steps of function template:

  1. You must have 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.
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
// The specialization of the template, which is specialized for some types
template<class T>
bool IsEqual(const T& left, const T& right) 
{
	return left == right;
}
//bool IsEqual(char* const& left, char* const& right)
//{
//	return strcmp(left, right) == 0;
//}
bool IsEqual(char* left, char*  right)
{
	return strcmp(left, right) == 0;
}
int main()
{
	int a = 0;
	int b = 10;
	cout << IsEqual(a, b) << endl;
	char p1[] = "hello";
	char p2[] = "hello";
	cout << IsEqual(p1, p2) << endl;
	return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;
template<class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
Template matching principle for special processing - this is recommended
//void Swap(vector<int>& a, vector<int>& b)
//{
//	a.swap(b);
//}

//Template specialization
template<>
void Swap<vector<int>>(vector<int>& a, vector<int>& b)
{
	a.swap(b);
}
int main()
{
	int x = 1;
	int y = 2;
	Swap(x, y);
	vector<int> v1 = { 1,2,30 };
	vector<int> v2 = { 20,10,30 };
	Swap(v1, v2);
	return 0;
}

Note: in general, if the function template encounters a type that cannot be processed or processed incorrectly, the function is usually given directly in order to simplify the implementation.

Class template specialization (multi use)

Full specialization

Full specialization is to determine all parameters in the template parameter list.

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;
template<class T1, class T2>
class Data
{
public:
	Data() 
	{ 
		cout << "Data<T1, T2>" << endl;
	}
private:
	T1 _d1;
	T2 _d2;
};
//class template specializations 
template<>
class Data<int, char>
{
public:
	Data() 
	{ 
		cout << "Data<int, char>" << endl; 
	}
private:
	int _d1;
	char _d2;
};
void TestVector()
{
	Data<int, int> d1;
	Data<int, char> d2;
}
int main()
{
	TestVector();
	return 0;
}

Partial specialization

Partial specialization: any specialized version of further conditional design for template parameters
Partial specialization: specialize some parameters in the template parameter class table.

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
// Specialize the second parameter to int
template <class T1>
class Data<T1, int> {
public:
	Data() { cout << "Data<T1, int>" << endl; }
private:
	T1 _d1;
	int _d2;
};

Partial specialization does not only refer to the specialization of some parameters, but a specialized version designed for the further conditional constraints of template parameters

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
using namespace std;
template<class T1, class T2>
class Data
{
public:
	Data() { cout << "Data<T1, T2>" << endl; }
private:
	T1 _d1;
	T2 _d2;
};
//The two parameters are partial specialization to pointer type
template <typename T1, typename T2>
class Data <T1*, T2*>
{
public:
	Data() { cout << "Data<T1*, T2*>" << endl; }

private:
	T1 _d1;
	T2 _d2;
};
//The two parameters are partially specialized into reference types
template <typename T1, typename T2>
class Data <T1&, T2&>
{
public:
	Data(const T1& d1, const T2& d2)
		: _d1(d1)
		, _d2(d2) 
	
	{
		cout << "Data<T1&, T2&>" << endl;
	}
private:
	const T1& _d1;
	const T2& _d2;
};
void test2()
{
	Data<double, int> d1; // Call specialized int version
	Data<int, double> d2; // Call the underlying template 
	Data<int*, int*> d3; // Call specialized pointer version
	Data<int&, int&> d4(1, 2); // Call specialized pointer version
}
int main()
{
	test2();
	return 0;
}

Note: partial specialization / semi specialization: it does not necessarily specify some parameters, but further limits the type of template parameters

Template separation compilation

Function template separation compilation

Separate compilation: a program (project) is implemented by several source files, and each source file is compiled separately to generate an object file. Finally, all object files are linked to form a single executable file, which is called separate compilation mode

If there are the following scenarios, the declaration of the template is separated from the definition, declared in the header file, and the definition is completed in the source file

// a.h
template<class T> 
T Add(const T& left, const T& right);
// a.cpp
template<class T> 
T Add(const T& left, const T& right) 
{
 	return left + right; 
}
// main.cpp
#include"a.h"
int main()
{
 Add(1, 2);
 Add(1.0, 2.0); 
 return 0; 
}

analysis:

Note:
Preprocessing: header file expansion, macro replacement, conditional compilation, removing comments... (convert. cpp to. i)
Compilation: syntax checking, generating assembly code (converting. i to. s)
Assembly: convert assembly code into binary machine code (convert. s to. o)
Link: put similar Where there is no function address in the o file, take the name to the target file, fill it in after finding it, and then merge the target file together to generate an executable file

Solution:

  1. Put the declaration and definition in a file "xxx.hpp" or XXX H actually, it's OK. This is recommended.

  1. The location of the template definition is explicitly instantiated. This method is not practical and is not recommended

Note:
Explicitly instantiating defects with one type has to be displayed, which is very troublesome

Class template separation compilation

.h
#pragma once
#include<iostream>
#include<vector>
using namespace std;
template<class T>
class Stack
{
public:
	Stack();
	~Stack();
	void Push(const T& x);
private:
	T* _a;
	int _top;
	int _capacity;
};


.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"a.h"
template<class T>
Stack<T>::Stack()
{
	_a = new T[10];
	_top = 0;
	_capacity = 10;
}

template<class T>
Stack<T>::~Stack()
{
	delete[] _a;
	_a = nullptr;
}
template<class T>
void Stack<T>::Push(const T& x)
{
	_a[_top] = x;
	++_top;
}

.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include"a.h"
int main()
{
	Stack<int> st1;
	Stack<double> st2;
	st1.Push(1);
	return 0;
}

resolvent:


Note: the solutions of class template separation compilation and function template separation compilation are similar

On demand instantiation of templates

When the content of the member function in the class template has a syntax problem and is not checked, the compiler will not report an error. The reason is that if the template is not instantiated, the compiler will not check the internal syntax error of the template. When we instantiate this class, the class template is instantiated on demand, and the member function we call will be instantiated.

Template summary

[advantages]

  1. Templates reuse code, save resources and develop iteratively faster. Therefore, the standard template library (STL) of C + + is produced
  2. Enhanced code flexibility

[defects]

  1. Templates can cause code bloat problems and lead to longer compilation times
  2. When a template compilation error occurs, the error information is very messy and it is difficult to locate the error

Keywords: C++ Back-end

Added by phpnow on Mon, 03 Jan 2022 11:20:27 +0200