Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

yet another insignificant programming notes... | HOME

TABLE OF CONTENTS (HIDE)


1. Introduc�on

C++ Programming Language 2. Example: STL's vector Template Class


3. Func�on Template
4. Class Template

Template and Generic Programming 5. Example: MyComplex Template Class

1. Introduction
We are familiar in passing value/variable into func�on. Instead of passing a variable, we pass a type (such as int, double, and Point) into template. Passing
type is known as generic programming, as we can program in generic type and invoke the code using a specific type.

The goal of generic programming is to write code that is independent of the data types. In C language, all codes are �ed to a specific data type. For container
data structures (such as array and structure), you need to specify the type of the elements. For algorithms (such as searching or sor�ng), the code works only for
a specific type, you need to rewrite the code for another type. Can we write a single sor�ng rou�ne that works on all types (or most of the types) by specifying
the type during invoca�on? Can we have a general container that can work on all types?

Template lets you program on generic type, instead of on a specific type. Template supports so-called parameterized type - i.e., you can use type as argument in
building a class or a func�on (in class template or func�on template). Template is extremely useful if a par�cular algorithm is to be applied to a variety of types,
e.g., a container class which contains elements, possibly of various types.

C++'s Standard Template Library (STL) provides template implementa�on of many container classes, such as vector, which can be used to hold elements of all
types. STL also provides generic representa�on of algorithm (such as searching and sor�ng), which works on the generic container.

2. Example: STL's vector Template Class


C/C++ built-in array has many drawbacks:
1. It is fixed-size and needs to be allocated with the fixed-size during declara�on. It does not support dynamic alloca�on. You cannot increase the size of an
array during execu�on.
2. Array does not provide index-bound check. You could use an index which is outside the array's bound.
3. You need to roll your own codes to compare two arrays (via ==), copy an array into another array (via assignment =), etc.

C++ provides a vector template class, as part of Standard Template Library (STL). It is defined in header <vector>, belonging to the namespace std. (In
compu�ng, a vector refers to an array-like structure that holds a set of direct-access elements of the same kinds, instead of mathema�cal n-component vector.)
vector is the most commonly used STL class, which provides an alterna�ve to the error-phone array, supports dynamic memory alloca�on and many
opera�ons (such as comparison and assignment).

vector is a template class, which can be instan�ated with a type, in the format: vector<int>, vector<double>, vector<string>. The same
template class can be used to handle many types, instead of repeatably wri�ng codes for each of the type.

1 /* Test vector template class (TestVectorTemplate.cpp) */


2 #include <iostream>
3 #include <vector>
4 #include <string>
5 using namespace std;
6
7 void print(const vector<int> & v);
8
9 int main() {
10 vector<int> v1(5); // Create a vector with 5 elements;
11
12 // Assign values into v1, using array-like index []
13 // You can retrieve the size of vector via size()
14 for (int i = 0; i < v1.size(); ++i) {
15 v1[i] = (i+1) * 2; // no index-bound check for []
16 }
17
18 // Print vector content, using at()
19 for (int i = 0; i < v1.size(); ++i) {
20 cout << v1.at(i) << " "; // do index-bound check with at()
21 }
22 cout << endl;
23

1 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

24 vector<int> v2; // Create a vector with 0 elements


25 // Assign v1 to v2 memberwise
26 v2 = v1;
27 for (int i = 0; i < v2.size(); ++i) {
28 cout << v2[i] << " ";
29 }
30 cout << endl;
31
32 // Compare 2 vectors memberwise
33 cout << boolalpha << (v1 == v2) << endl;
34
35 // Append more elements - dynamically allocate memory
36 v1.push_back(80);
37 v1.push_back(81);
38 for (int i = 0; i < v1.size(); ++i) {
39 cout << v1[i] << " ";
40 }
41 cout << endl;
42
43 // Remove element from the end
44 v1.pop_back();
45 for (int i = 0; i < v1.size(); ++i) {
46 cout << v1[i] << " ";
47 }
48 cout << endl;
49
50 vector<string> v3; // Create a vector of string with 0 element
51 v3.push_back("A for Apple"); // append new elements
52 v3.push_back("B for Boy");
53 for (int i = 0; i < v3.size(); ++i) {
54 cout << v3[i] << " ";
55 }
56 cout << endl;
57 }

Program Notes:
You can instan�ate a vector of int via declara�on vector<int> v1(n), where n specifies the ini�al number of elements.
You can use v1.size() to get the current size (number of elements) of the vector.
You can directly access element via v1[i] or v1.at(i). The [] operator does not perform index-bound check; whereas at() does. Try issuing an out-
of-bound index via [] and at() and observe the result.
You can assign a vector into another vector via the assignment operator (=). The assignment is carried out memberwise.
You can compare two vectors memberwise via the comparison operators (==, !=).
You can append/remove element from the end via push_back() and pop_back(). The size of vector will be adjusted and memory allocated
automa�cally.
You can also create vector of other types, such as vector<string>, vector<double>, etc. The bigger advantage of template class is the same
algorithm and opera�on can be applied to different types - you do not need to write separate codes for different types.

3. Function Template
A func�on template is a generic func�on that is defined on a generic type for which a specific type can be subs�tuted. Compiler will generate a func�on for each
specific type used. Because types are used in the func�on parameters, they are also called parameterized types.

The syntax of defining func�on template is:

template <typename T> OR template <class T>


return-type function-name(function-parameter-list) { ...... }

Similar to func�on's parameter-list, which passes variables (e.g., int number), the template's parameter list passes types.

Example 1
1 /* Test Function Template (FuncationTemplate.cpp) */
2 #include <iostream>
3 using namespace std;
4
5 template <typename T>
6 void mySwap(T &a, T &b);
7 // Swap two variables of generic type passed-by-reference
8 // There is a version of swap() in <iostream>
9
10 int main() {
11 int i1 = 1, i2 = 2;

2 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

12 mySwap(i1, i2); // Compiler generates mySwap(int &, int &)


13 cout << "i1 is " << i1 << ", i2 is " << i2 << endl;
14
15 char c1 = 'a', c2 = 'b';
16 mySwap(c1, c2); // Compiler generates mySwap(char &, char &)
17 cout << "c1 is " << c1 << ", c2 is " << c2 << endl;
18
19 double d1 = 1.1, d2 = 2.2;
20 mySwap(d1, d2); // Compiler generates mySwap(double &, double &)
21 cout << "d1 is " << d1 << ", d2 is " << d2 << endl;
22
23 // mySwap(i1, d1);
24 // error: no matching function for call to 'mySwap(int&, double&)'
25 // note: candidate is:
26 // note: template<class T> void mySwap(T&, T&)
27 }
28
29 template <typename T>
30 void mySwap(T &a, T &b) {
31 T temp;
32 temp = a;
33 a = b;
34 b = temp;
35 }

Take note that the C++ compiler generate a version of the code for each type used in the program, in a process known as instan�a�on of template. For example,
with type of int, the following code will be generated by the compiler:

void mySwap(int &a, int &b) {


int temp;
temp = a;
a = b;
b = temp;
}

There is no improvement in term of execu�on speed or memory usage. But there is a big improvement in programmer's produc�vity, ease-of-use and ease-of-
maintenance.

Also, the above code can handle the fundamental types (such as int, double), but not some types such as array. It, however, works for objects and structs,
thanks to the memberwise assignment.

You could use <typename T> or <class T> in the template parameter list. The keywords typename and class serve the same purpose.

Example 2
1 /* Test function Template (TestFunctionTemplate.cpp) */
2 #include <iostream>
3 using namespace std;
4
5 template<typename T>
6 T abs(T value) {
7 T result; // result's type is also T
8 result = (value >= 0) ? value : -value;
9 return result;
10 }
11
12 int main() {
13 int i = -5;
14 cout << abs(i) << endl;
15
16 double d = -55.5;
17 cout << abs(d) << endl;
18
19 float f = -555.5f;
20 cout << abs(f) << endl;
21 }

The compiler creates three versions of the abs func�on based on the func�on template, for types of int, double, and float.

Function Template Overloading


1 /* Test Function Template Overloading (FuncationTemplateOverloading.cpp) */
2 #include <iostream>
3 using namespace std;
4
5 template <typename T>
6 void mySwap(T &a, T &b);
7 // Swap two variables of generic fundamental type

3 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

8
9 template <typename T>
10 void mySwap(T a[], T b[], int size);
11 // Swap two arrays of generic type
12
13 template <typename T>
14 void print(const T * const array, int size);
15 // Print an array of generic type
16
17 int main() {
18 int i1 = 1, i2 = 2;
19 mySwap(i1, i2); // Compiler generates mySwap(int &, int &)
20 cout << "i1 is " << i1 << ", i2 is " << i2 << endl;
21
22 const int SIZE = 3;
23 int ar1[] = {1, 2, 3}, ar2[] = {4, 5, 6};
24 mySwap(ar1, ar2, SIZE);
25 print(ar1, SIZE);
26 print(ar2, SIZE);
27 }
28
29 template <typename T>
30 void mySwap(T &a, T &b) {
31 T temp;
32 temp = a;
33 a = b;
34 b = temp;
35 }
36
37 template <typename T>
38 void mySwap(T a[], T b[], int size) {
39 T temp;
40 for (int i = 0; i < size; ++i) {
41 temp = a[i];
42 a[i] = b[i];
43 b[i] = temp;
44 }
45 }
46
47 template <typename T>
48 void print(const T * const array, int size) {
49 cout << "(";
50 for (int i = 0; i < size; ++i) {
51 cout << array[i];
52 if (i < size - 1) cout << ",";
53 }
54 cout << ")" << endl;
55 }

Explicit Specialization
1 /* Test Function Template Explicit Specialization (FuncationTemplateSpecialization.cpp) */
2 #include <iostream>
3 using namespace std;
4
5
6 template <typename T>
7 void mySwap(T &a, T &b); // Template
8
9 template <>
10 void mySwap<int>(int &a, int &b);
11 // Explicit Specialization for type int
12
13 int main() {
14 double d1 = 1, d2 = 2;
15 mySwap(d1, d2); // use template
16
17 int i1 = 1, i2 = 2;
18 mySwap(i1, i2); // use specialization
19 }
20
21 template <typename T>
22 void mySwap(T &a, T &b) {
23 cout << "Template" << endl;
24 T temp;
25 temp = a;

4 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

26 a = b;
27 b = temp;
28 }
29
30 template <>
31 void mySwap<int>(int &a, int &b) {
32 cout << "Specialization" << endl;
33 int temp;
34 temp = a;
35 a = b;
36 b = temp;
37 }
38

Take note that if there is any non-template defini�on that matches the func�on call. The non-template version will take precedence over explicit specializa�on,
then template.

4. Class Template
The syntax for defining a class template is as follow, where T is a placeholder for a type, to be provided by the user.

template <class T> // OR template <typename T>


class ClassName {
......
}

The keywords class and typename (newer and more appropriate) are synonymous in the defini�on of template.

To use the template defined, use the syntax ClassName<actual-type>.

For Example,

1 /*
2 * Test Class Template (TestClassTemplate.cpp)
3 */
4 #include <iostream>
5 using namespace std;
6
7 template <typename T>
8 class Number {
9 private:
10 T value;
11 public:
12 Number(T value) { this->value = value; };
13 T getValue() { return value; }
14 void setValue(T value) { this->value = value; };
15 };
16
17 int main() {
18 Number<int> i(55);
19 cout << i.getValue() << endl;
20
21 Number<double> d(55.66);
22 cout << d.getValue() << endl;
23
24 Number<char> c('a');
25 cout << c.getValue() << endl;
26
27 Number<string> s("Hello");
28 cout << s.getValue() << endl;
29 }

Separating Template Function Declaration and Definition


If you separate the func�on implementa�on, you need to use keyword template <typename T> on each of the func�on implementa�on. For example,

template <typename T>


T Number<T>::getValue() {
return value;
}

Keep All Template Codes in the Header file


Templates are not class nor member func�on defini�on. They are instruc�ons to the C++ compiler how to generate the class defini�on. Hence, placing member
func�ons in a separate file will not work. All template codes shall be placed in the header file - to be included in all files using the template. Template cannot be
compiled separately.

5 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

A par�cular realiza�on of template is called an instan�a�on or specializa�on. The C++ compiler generate a class for each of the parameterized type used in the
program.

More than one Type Parameters


To use more than one type parameters in a template:

template <typename T1, typename T2, ....>


class ClassName { ...... }

Default Type
You can also provide default type in template. For example,

template <typename T = int>


class ClassName { ...... }

To instan�ate with the default type, use ClassName<>.

Specialization
// General Template
template <typename T>
class Complex { ...... }

// Specialization for type double


template <>
class Complex<double> { ...... }

// Specialization for type int


template <>
class Complex<int> { ....... }

The specializa�on version will be matched, if available.

5. Example: MyComplex Template Class

MyComplex.h
1 /*
2 * The MyComplex template class header (MyComplex.h)
3 * All template codes are kept in the header, to be included in program
4 * (Follow, modified and simplified from GNU GCC complex template class.)
5 */
6 #ifndef MY_COMPLEX_H
7 #define MY_COMPLEX_H
8
9 #include <iostream>
10
11 // Forward declaration
12 template <typename T> class MyComplex;
13
14 template <typename T>
15 std::ostream & operator<< (std::ostream & out, const MyComplex<T> & c);
16 template <typename T>
17 std::istream & operator>> (std::istream & in, MyComplex<T> & c);
18
19 // MyComplex template class declaration
20 template <typename T>
21 class MyComplex {
22 private:
23 T real, imag;
24
25 public:
26 // Constructor
27 explicit MyComplex<T> (T real = 0, T imag = 0)
28 : real(real), imag(imag) { }
29
30 // Overload += operator for c1 += c2
31 MyComplex<T> & operator+= (const MyComplex<T> & rhs) {
32 real += rhs.real;
33 imag += rhs.imag;
34 return *this;
35 }
36
37 // Overload += operator for c1 += value
38 MyComplex<T> & operator+= (T value) {

6 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

39 real += value;
40 return *this;
41 }
42
43 // Overload comparison == operator for c1 == c2
44 bool operator== (const MyComplex<T> & rhs) const {
45 return (real == rhs.real && imag == rhs.imag);
46 }
47
48 // Overload comparison != operator for c1 != c2
49 bool operator!= (const MyComplex<T> & rhs) const {
50 return !(*this == rhs);
51 }
52
53 // Overload prefix increment operator ++c
54 // (Separate implementation for illustration)
55 MyComplex<T> & operator++ ();
56
57 // Overload postfix increment operator c++
58 const MyComplex<T> operator++ (int dummy);
59
60 /* friends */
61
62 // (Separate implementation for illustration)
63 friend std::ostream & operator<< <>(std::ostream & out, const MyComplex<T> & c); // out << c
64 friend std::istream & operator>> <>(std::istream & in, MyComplex<T> & c); // in >> c
65
66 // Overloading + operator for c1 + c2
67 // (inline implementation for illustration)
68 friend const MyComplex<T> operator+ (const MyComplex<T> & lhs, const MyComplex<T> & rhs) {
69 MyComplex<T> result(lhs);
70 result += rhs; // uses overload +=
71 return result;
72 }
73
74 // Overloading + operator for c + double
75 friend const MyComplex<T> operator+ (const MyComplex<T> & lhs, T value) {
76 MyComplex<T> result(lhs);
77 result += value; // uses overload +=
78 return result;
79 }
80
81 // Overloading + operator for double + c
82 friend const MyComplex<T> operator+ (T value, const MyComplex<T> & rhs) {
83 return rhs + value; // swap and use above function
84 }
85 };
86
87 // Overload prefix increment operator ++c
88 template <typename T>
89 MyComplex<T> & MyComplex<T>::operator++ () {
90 ++real; // increment real part only
91 return *this;
92 }
93
94 // Overload postfix increment operator c++
95 template <typename T>
96 const MyComplex<T> MyComplex<T>::operator++ (int dummy) {
97 MyComplex<T> saved(*this);
98 ++real; // increment real part only
99 return saved;
100 }
101
102 /* Definition of friend functions */
103
104 // Overload stream insertion operator out << c (friend)
105 template <typename T>
106 std::ostream & operator<< (std::ostream & out, const MyComplex<T> & c) {
107 out << '(' << c.real << ',' << c.imag << ')';
108 return out;
109 }
110
111 // Overload stream extraction operator in >> c (friend)
112 template <typename T>
113 std::istream & operator>> (std::istream & in, MyComplex<T> & c) {
114 T inReal, inImag;

7 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

115 char inChar;


116 bool validInput = false;
117 // Input shall be in the format "(real,imag)"
118 in >> inChar;
119 if (inChar == '(') {
120 in >> inReal >> inChar;
121 if (inChar == ',') {
122 in >> inImag >> inChar;
123 if (inChar == ')') {
124 c = MyComplex<T>(inReal, inImag);
125 validInput = true;
126 }
127 }
128 }
129 if (!validInput) in.setstate(std::ios_base::failbit);
130 return in;
131 }
132
133 #endif

Program Notes:
[TODO]

TestMyComplex.cpp
1 /* Test Driver for MyComplex template class (TestMyComplex.cpp) */
2 #include <iostream>
3 #include <iomanip>
4 #include "MyComplex.h"
5
6 int main() {
7 std::cout << std::fixed << std::setprecision(2);
8
9 MyComplex<double> c1(3.1, 4.2);
10 std::cout << c1 << std::endl; // (3.10,4.20)
11 MyComplex<double> c2(3.1);
12 std::cout << c2 << std::endl; // (3.10,0.00)
13
14 MyComplex<double> c3 = c1 + c2;
15 std::cout << c3 << std::endl; // (6.20,4.20)
16 c3 = c1 + 2.1;
17 std::cout << c3 << std::endl; // (5.20,4.20)
18 c3 = 2.2 + c1;
19 std::cout << c3 << std::endl; // (5.30,4.20)
20
21 c3 += c1;
22 std::cout << c3 << std::endl; // (8.40,8.40)
23 c3 += 2.3;
24 std::cout << c3 << std::endl; // (10.70,8.40)
25
26 std::cout << ++c3 << std::endl; // (11.70,8.40)
27 std::cout << c3++ << std::endl; // (11.70,8.40)
28 std::cout << c3 << std::endl; // (12.70,8.40)
29
30 // c1+c2 = c3; // error: c1+c2 returns a const
31 // c1++++; // error: c1++ returns a const
32
33 // MyComplex<int> c4 = 5; // error: implicit conversion disabled
34 MyComplex<int> c4 = (MyComplex<int>)5; // explicit type casting allowed
35 std::cout << c4 << std::endl; // (5,0)
36
37 MyComplex<int> c5;
38 std::cout << "Enter a complex number in (real,imag): ";
39 std::cin >> c5;
40 if (std::cin.good()) {
41 std::cout << c5 << std::endl;
42 } else {
43 std::cerr << "Invalid input" << std::endl;
44 }
45 return 0;
46 }

Program Notes:
[TODO]

8 of 9 22/03/2020, 19:47
Object-oriented Programming (OOP) in C++ https://www3.ntu.edu.sg/home/ehchua/programming/cpp/cp8_Template...

Link to "C++ References & Resources"

Latest version tested: Cygwin/MinGW GCC 4.6.2


Last modified: May, 2013

Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan (ehchua@ntu.edu.sg) | HOME

9 of 9 22/03/2020, 19:47

You might also like