C + + generic programming

This article introduces another branch of C + + programming parallel to object-oriented programming -- Generic Programming. This article mainly introduces three parts: function template, class template and member template

If there is any infringement, please contact to delete. If there is any error, please correct it. Thank you

Generic Programming

  • Template is an important idea of generic programming. STL(Standard Template Library) is an example of template implementation

Function template

  • Compared with function overloading (functions with the same function name and different parameter list in the same scope), function template only needs one function to realize some functions of function overloading (functions with the same number of parameters and different types need to define multiple functions with different parameter lists of the same name)
template<typename T, typename Y>  // You can also write template < class T, Class Y > where class and typename have the same effect
void tfunc(T& t, Y& y) {
	cout << t << " " << y << endl;
}

int n = 2;
double d = 2.1;
tfunc(n, d);

// Operation result: 2 2.1
  • Function template materialization is to process one (or several) types to be processed separately, and need to write an implementation separately, in the form of template < > void fun (type & T); the materialization of function template and common function can exist at the same time, and the calling sequence is common function > function template materialization > template function
struct Node {
	int val;
	Node* next;
};

// Function template
template<typename T> 
void tfunc(const T& t) {
	cout << "template: " << t << endl;
}

// Function template materialization (for processing Node type data)
template<> void tfunc<Node>(const Node& node) {
	cout << "template<Node>: " << node.val << endl;
}

// Function template materialization (for int type data)
template<> void tfunc<int>(const int& n) {
	cout << "template<int>: " << n << endl;
}

// Ordinary function
void tfunc(const int& n) {
	cout << "tfunc(): " << n << endl;
}

double d = 2.1;
tfunc(d);    // Function template does not specify function of double type, calling template
Node node{ 2, nullptr };
tfunc(node); // Function template materializes Node type functions and calls function template materialization
int n = 2;
tfunc(n);    // The function template specifies int type functions, but there are also ordinary functions that call ordinary functions
  • Function template instantiation enables the compiler to generate function definitions of the specified type without writing the implementation of the function, in the form of template void fun (type & T);
// Function template
template<typename T> 
void tfunc(const T& t) {
	cout << "template: " << t << endl;
}

// The function template instantiation does not need to write the implementation of the function. The compiler will generate template specific functions of this type
template void tfunc<char>(const char& c);

Class template

  • Class templates can specify default template parameters (function templates are not allowed). Like the default value of function parameters, the default type must be assigned continuously from right to left. If the type is passed when the object is instantiated, the default type will be overwritten, which is the same as the function parameters
  • When creating an object, you need to pass the template parameter list, which is added after the class name ClassName < typename T > classn; if the class's template parameter list has a default value, you can not pass the template parameter, but you must add < > such as ClassName < > classn; when creating a heap object, you need to add the template parameter list after all the class names, such as ClassName < typename T > * cla SSN = new ClassName < typename T >; except for the class, the template parameter list is generally added to the ClassName in other places
template<typename T = int, typename Y = char> // Template default parameters are specified here. Some of them must be specified from right to left
class Test {
public:
	Test(T t, Y y) : t(t), y(y) {

	}

	void tfunc();

private:
	T t;
	Y y;
};

template<typename T, typename Y> // The function of a class template is implemented outside the class. The template parameter list needs to be added, but the specified default template parameter does not need to be added
void Test<T, Y>::tfunc() { // Template parameter is required to use Test out of class
	cout << t << " " << y << endl;
}

int n = 2;
double d = 2.1;
Test<int, double> test(n, d); // Here, if the default template parameter is used, it can be defined as test < > Test (int (2), char ('a '));
test.tfunc();

// Operation result: 2 2.1
  • There are two ways to transfer the parameters of a class template after it is inherited. One is to specify a fixed type for the parent class directly when the child class inherits the parent class, and the other is to transfer the parameters through the parameter list of the child class template
// ======Test one======
template<typename T, typename Y>
class A {
public:
	A(T t, Y y) {

	}
};

class Test : public A<int, double> { // The parent class is a class template and the child class is a common class
public:
	Test() : A<int, double>(2, 2.1) {

	}
};

Test();

// ======Test two======
template<typename T, typename Y>
class A {
public:
	A(T t) {

	}
};

template<typename X, typename Z, typename P>
class Test : public A<X, P> {
public:
	Test(X x, Z z, P p) : A<X, P>(x) {

	}
};

Test<int, double, char>(int(2), double(2.1), char('a'));
  • The polymorphism of class template can be divided into two types when creating objects: subclass without template (cfath < short, char > * CF = new cson;) and subclass with template (cfath < short, char > * CF = new cson < short, int, char >). The template parameter list of subclass and parent can be different, but it must be well matched
// ======Test one======
template<typename T, typename Y> 
class A {
public:
	virtual void tfunc(T t, Y y) = 0;
};

class Test : public A<int, double> { 
public:
	virtual void tfunc(int n, double d) {
		cout << n << " " << d << endl;
	}
};

// The parent class is a class template, and the child class is a common class. In the case of polymorphism, the parent class needs to specify template parameters, and the child class is not needed
A<int, double>* a = new Test;
a->tfunc(2, 2.1);
// Operation result: 2 2.1

// ======Test two======
template<typename T, typename Y> 
class A {
public:
	virtual void tfunc(T t, Y y) = 0;
};

template<typename X, typename Z, typename P>
class Test : public A<X, P> {
public:
	virtual void tfunc(X x, P p) {
		cout << x << " " << p << endl;
	}
};

// The parent class is a class template and the child class is a class template. In the case of polymorphism, both the parent class and the child class need to specify template parameters
A<int, double>* a = new Test<int, char, double>;
a->tfunc(2, 2.1);
// Operation result: 2 2.1

Member template

  • A member template is simply a template in a template
class Base1 { };
class Base2 { };

class Test1 : public Base1 { };
class Test2 : public Base2 { };

template<typename T1, typename T2> 
class Pair {
public:
	T1 t1;
	T2 t2;

	Pair(T1 t1, T2 t2) : t1(t1), t2(t2) {

	}

    // Member templates in class templates
	template<typename U1, typename U2>
	Pair(const Pair<U1, U2>& pair) : t1(pair.t1), t2(pair.t2){

	}
};

Pair<Base1*, Base2*>(Pair<Test1*, Test2*>(new Test1, new Test2));

Unless otherwise specified, the above tests are carried out under win10 vs2017 64bit compiler

Published 30 original articles, won praise 7, visited 750
Private letter follow

Keywords: Programming

Added by simoesp on Wed, 05 Feb 2020 10:27:23 +0200