Details on C++ Generic programming
- 2020-07-21 09:11:45
- OfStack
Generic programming has the same goals as object-oriented programming, even though techniques for reusing code and abstracting generic concepts are simpler. Whereas object-oriented programming emphasizes the data aspect of programming, generic programming emphasizes independence from specific data types.
This article introduces the other branch of C++ programming that is parallel to object-oriented programming -- generic programming. This article mainly introduces function templates, class templates and member templates
If there is infringement, please contact delete, if there is a mistake, welcome to correct, thank you
Generic programming
Templates are one of the important ideas of generic programming. STL(Standard Template Library, standard template library) is an example of using templates
A function template
Compared with function overloading (functions with the same name and different parameter lists in the scope of 1), function template only needs 1 function to realize some functions of function overloading (functions with the same parameter number and different types need to define multiple functions with different parameter lists of the same name).
template<typename T, typename Y> // I could have written this template<class T, class Y> Here the class and typename The same effect
void tfunc(T& t, Y& y) {
cout << t << " " << y << endl;
}
int n = 2;
double d = 2.1;
tfunc(n, d);
// Operation results: 2 2.1
Function template materialization is to process one (several) of the types to be processed separately and write one implementation in the form of template < > void fun(type & t); , the materialized function template and the normal function can exist at the same time, and the call order is the normal function > Function template materialization > Template function
// ====== test 1 : Function templates are specific to a particular data type ======
struct Node {
int val;
Node* next;
};
// A function template
template<typename T>
void tfunc(const T& t) {
cout << "template: " << t << endl;
}
// Function template materialization ( To deal with Node Type data )
template<>
void tfunc<Node>(const Node& node) {
cout << "template<Node>: " << node.val << endl;
}
// Function template materialization ( To deal with int Type data )
template<>
void tfunc<int>(const int& n) {
cout << "template<int>: " << n << endl;
}
// Common function
void tfunc(const int& n) {
cout << "tfunc(): " << n << endl;
}
double d = 2.1;
tfunc(d); // The function template is not materialized double Type function that calls the template
Node node{ 2, nullptr };
tfunc(node); // Function template materialization Node Type a function that calls the materialization of a function template
int n = 2;
tfunc(n); // Function template materialization int Type functions, there are normal functions, call normal functions
// ====== test 2 : The function template is partially materialized ======
template<typename T1, typename T2>
void tfunc(T1 t1, T2 t2) {
cout << typeid(T1).name() << " and " << typeid(T2).name() <<": " << t1 << " " << t2 << endl;
}
template<typename T1>
void tfunc(T1 t1, int i) {
cout << typeid(T1).name() << " and " << "int: " << t1 << " " << i << endl;
}
template<typename T2>
void tfunc(long l, T2 t2) {
cout << "long and " << typeid(T2).name() << ": " << l << " " << t2 << endl;
}
template<>
void tfunc(short l, int i) {
cout << "long and int: " << l << " " << i << endl;
}
// Call the above separately 4 A template function
tfunc(char('c'), char('c'));
tfunc(char('c'), int(10));
tfunc(long(10), char('c'));
tfunc(short(10), int(10));
Function templates are instantiated to allow the compiler to generate function definitions of the specified type without writing the implementation of the function as template void fun(type) & t);
// A function template
template<typename T>
void tfunc(const T& t) {
cout << "template: " << t << endl;
}
// Function template instantiation. Instead of writing the implementation of the function, the compiler generates template externalization functions of this type
template void tfunc<char>(const char& c);
Class template
Class templates can specify default template parameters (function templates cannot), like the default value of function parameters, which must be assigned continuously from right to left. If an object is instantiated with a type passed, the default type will be overridden, like function parameters
To create an object, you need to pass in the template parameter list, which is appended to the class name ClassName
<
typename T
>
classN; If the class template parameter column
The table has default values, you can not pass template parameters, but 1 must be added
<
>
Such as ClassName
<
>
classN; When creating heap objects, all class names are followed by a template parameter list, such as ClassName
<
typename T
>
* classN = new ClassName
<
typename T
>
; Anywhere ClassName appears except within the class, the template parameter list is generally added
template<typename T = int, typename Y = char> // The template default parameters are specified here, and part of the specification 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 functions of the class template are implemented outside of the class and require a list of template parameters, but not the specified default template parameters
void Test<T, Y>::tfunc() { // Outside the class Test Template parameters need to be added
cout << t << " " << y << endl;
}
int n = 2;
double d = 2.1;
Test<int, double> test(n, d); // The default template parameter can be defined as Test<> test(int(2), char('a'));
test.tfunc();
// Operation results: 2 2.1
There are mainly two ways to pass parameters after class template is inherited. One is to specify fixed types for the parent class directly when the child class inherits the parent class, and the other is to pass through the parameter list of the child class template
// ====== test 1 ======
template<typename T, typename Y>
class A {
public:
A(T t, Y y) {
}
};
class Test : public A<int, double> { // The superclass is a class template, and the subclass is a normal class
public:
Test() : A<int, double>(2, 2.1) {
}
};
Test();
// ====== test 2 ======
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 templates, when creating objects, is divided into subclasses without templates (CFather
<
short, char
>
* cf = new CSon;) And subclasses have templates (CFather
<
short, char
>
*cf = new CSon
<
short, int, char
>
), the subclass and the superclass template parameter list may not be the same, but the 1 must correspond well
// ====== test 1 ======
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 superclass is the class template, the subclass is the ordinary class, in the polymorphic case the superclass needs to specify the template parameter, the subclass does not
A<int, double>* a = new Test;
a->tfunc(2, 2.1);
// Operation results: 2 2.1
// ====== test 2 ======
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 superclass is the class template, and the subclass is the class template. In the case of polymorphism, both the superclass and the subclass need to specify template parameters
A<int, double>* a = new Test<int, char, double>;
a->tfunc(2, 2.1);
// Operation results: 2 2.1
The reification of a template can be divided into two types: partial reification and full reification
template<typename T1, typename T2>
class Test {
public:
Test() {
cout << "T1 and T2" << endl;
}
};
// Partial reification
template<typename T1>
class Test<T1, int> {
public:
Test() {
cout << "T1 and int" << endl;
}
};
// Partial reification
template<typename T2>
class Test<long, T2> {
public:
Test() {
cout << "long and T2" << endl;
}
};
// Full concretization
template<>
class Test<long, int> {
public:
Test() {
cout << "long and int" << endl;
}
};
// Create the above separately 4 A class
Test<char, char>();
Test<char, int>();
Test<long, char>();
Test<long, int>();
Members of the template
A member template is simply a template within 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 were performed under the win10 vs2017 64bit compiler
conclusion
Above is the site to introduce C++ generic programming, I hope to help you!