CSE2305/CSC2050 - Object-Oriented Software Engineering
Week 10

 

Topic 20: C++ Templates


Synopsis


Remember¤ genericity¤?


Recall the linked list example

struct NodeRec { int data; struct NodeRec* next; }; typedef struct NodeRec Node;

struct ListOfInt { Node* head; Node* current; };

void LOI_Initialize(ListOfInt* list); void LOI_InsertBefore(ListOfInt* list, int data); void LOI_InsertAfter(ListOfInt* list, int data); void LOI_DeleteCurrent(ListOfInt* list); int LOI_First(ListOfInt* list); int LOI_Next(ListOfInt* list);

struct NodeRec { StudRec data; struct NodeRec* next; }; typedef struct NodeRec Node;

struct ListOfStudec { Node* head; Node* current; };

void LOSR_Initialize(ListOfStudRec* list); void LOSR_InsertBefore(ListOfStudRec* list, StudRec data); void LOSR_InsertAfter(ListOfStudRec* list, StudRec data); void LOSR_DeleteCurrent(ListOfStudRec* list); StudRec LOSR_First(ListOfStudRec* list); StudRec LOSR_Next(ListOfStudRec* list);

#define DECLARE_LIST_OF(TYPE, PREFIX) \ \ struct NodeFor##TYPE##Rec \ { \ TYPE data; \ struct NodeFor##TYPE##Rec* next; \ }; \ \ typedef struct NodeFor##TYPE##Rec NodeFor##Type; \ \ struct ListOf##TYPE \ { \ NodeFor##TYPE* head; \ NodeFor##TYPE* current; \ }; \ \ void PREFIX##_Initialize(ListOf##TYPE* list); \ void PREFIX##_InsertBefore(ListOf##TYPE* list, TYPE data); \ void PREFIX##_InsertAfter(ListOf##TYPE* list, TYPE data); \ void PREFIX##_DeleteCurrent(ListOf##TYPE* list); \ TYPE PREFIX##_First(ListOf##TYPE* list); \ TYPE PREFIX##_Next(ListOf##TYPE* list);


A better solution


Creating a C++ template

class ListOfInt { public:

ListOfInt(void);

void InsertBefore(int data); void InsertAfter(int data); void DeleteCurrent(void); int First(void); int Next(void);

private: struct Node { int data; Node* next; };

Node* head; Node* current; };

class ListOfStudRec { public:

ListOfStudRec(void);

void InsertBefore(StudRec data); void InsertAfter(StudRec data); void DeleteCurrent(void); StudRec First(void); StudRec Next(void);

private: struct Node { StudRec data; Node* next; };

Node* head; Node* current; };

template <class TYPE> class ListOf { public:

ListOf(void);

void InsertBefore(TYPE data); void InsertAfter(TYPE data); void DeleteCurrent(void); TYPE First(void); TYPE Next(void);

private: struct Node { TYPE data; Node* next; };

Node* head; Node* current; };


Using a C++ template

class ListOf<int>; // EQUIVALENT TO ListOfInt

class ListOf<StudRec>; // EQUIVALENT TO ListOfStudRec

class ListOf<string> // CLASS TO STORE string OBJECTS

class ListOf<Target> // CLASS TO STORE Target OBJECTS

class ListOf<Nominee>; // IN THE CATEGORY // "Best Template in a Supporting Role"

class ListOf<Winner>; // AND THE WINNER IS...Shirley Template!

class ListOf< ListOf<int> >; // WOW!

int main(void) { ListOf<double> marks; // COMPILER CREATES THIS TYPE ListOf<int> ids; // AND THIS TYPE double nextmark; int nextid;

while (cin >> nextid >> nextmark) { ids.InsertAfter(nextid); marks.InsertAfter(nextmark); }

// ETC... };


How to design a templated class¤


What parameters can a template have?

template <class KEYTYPE, class DATATYPE> class AssociativeArray { public: AssociativeArray(void); ~AssociativeArray(void);

DATATYPE& operator[](const KEYTYPE& key);

ListOf<KEYTYPE> Keys(void); ListOf<DATATYPE> Values(void);

private: // MAGIC CODE TO MAKE IT ALL WORK :-) };

// AND LATER

int main(void) { AssociativeArray<string, double> result;

result["Damian"] = 100.0; // SET THE EXAM result["Boris"] = 49.9; // WAS DRUNK result["Ai Joo"] = 77.7 // GOOD STUDENT result["Damien"] = 66.6 // EVIL STUDENT

string name; while (cin >> name) { cout << result[name] << endl; } }

template <int MAXSCORE, int PASSMARK> class ExamResults { public: ExamResults(ListOf<ints> ids, ListOf<double> scores); ~ExamResults(void);

void PrintPasses(void) { double nextmark; int nextid; while (GetNextMark(nextid,nextmark)) { if (nextmark>=PASSMARK) { cout << nextid << ": " << nextmark/MAXSCORE*100 << endl; } } }

private: // MAGIC CODE TO MAKE IT ALL WORK :-)

bool GetNextResult(int& id, double& mark); };

// AND LATER

int main(int argc, char* argv[]) { ListOf<int> idlist = getIDList($argv[0]); ListOf<double> marklist = getMarkList($argv[0]);

ExamResults<100,50> passHalf(idlist, marklist); ExamResults<100,90> passReal(idlist, marklist);

cout << "Normally pass at 50%..." << endl; passHalf.PrintPasses();

cout << "But today pass at 90%..." << endl; passReal.PrintPasses(); }


Function templates

template <class DATATYPE> DATATYPE max(const DATATYPE& d1, const DATATYPE& d2) { return (d1>d2) ? d1 : d2; }

// AND LATER...

int main(void) { string s1 = "cat"; string s2 = "dog";

cout << max(1,2) << endl; cout << max(1.1,2.2) << endl; cout << max(s1,s2) << endl;

cout << max("cat","dog") << endl; cout << max(1,2.2) << endl; }


Coping with exceptional behaviour¤

char* max(const char*& d1, const char*& d2) { return (d1>d2) ? d1 : d2; }

template <> char* max(const char*& d1, const char*& d2) { return (strcmp(d1,d2)>0) ? d1 : d2; }


A scary example to finish with

template <long N> class Factorial { public: long Value(void) { return N * fn_1.Value(); }

private: Factorial<N-1> fn_1; };

template <> class Factorial<0> { public: long Value(void) { return 1; } };

int main(void) { Factorial<15> f15;

cout << f15.Value() << endl; }


Reading

Winston: Chapter 49

Stroustrup: Chapter 13

Lippman/Lajoie: Chapters 10 & 16

 


This material is part of the CSE2305/CSC2050 - Object-Oriented Software Engineering course.
Copyright © Damian Conway, 1998. All rights reserved.

Last updated: Tue Jul 6 11:34:12 1999