Home Page
The Basics
Arrays
Classes
Abstract Data Types
Dynamic Memory Allocation
Operator Overloading
Lists
C++ Style Strings
Linked Lists
Stacks and Queues
Variable Data Types

Sorting
Templates
recall back to the sorting routines we wrote way back.  There are many times that a sort could be used for several different types of data.  This is where generic programming comes into play.

A template is related to a macro in that in a C macro, you can use #define to replace a given symbol with a set value throughout a program.  

Example of C macro:
     #define sqr(x)   x*x

this is a function that will return the square of  an input.  To use it you would code the following:

int a = 7;
cout << sqr(a);
when this is compiled, the compiler will replace the (a) with (a*a)

what if you coded:??
          int c,d;
          cout << sqr(c+d);

You would think this would work but in fact it will not give you the result you may think.  Look closely…  when it is compiled, the compiler replaces what is within the parentheses with what is specified in the macro.  In this case it would be   (c+d*c+d).  Due to the hierarchy of operands this would be equivalent to saying   (c+(d*c)+d)   instead of   ((c+d)*(c+d))  

This leads us to the use of templates.  Lets recall a standard swap function:

Standard function:

void swap(string &a, string &b)
{
     string temp;
     temp = a;
     a = b;
     b = temp;
}

Now to convert this to a template, the only thing we need to change are the highlighted variables;  A template is basically a macro on steroids.  It will even let you take entire functions and classes and treat them as macros.

Template:

template <class T>          // must ALWAYS have this line for a template
void swap(T&a, T&b)
{
T temp;
temp = a;
a = b:
b = temp;
}

Note that whenever you see 'T' , it represents a type of some sort.  Whenever it is called it will insert the type of the call and generate code for a swap of that type.  This won't compile at this stage.  You first need to create an instance for it's use because the compiler doesn't know what the type T is.

Templates will go in your .h file (or above the main() in a small coding where you would generally put your class definitions.  Then in the main() you can code:

main()
{
int a,b;
double c,d;
string e,f;

swap(a,b);
swap(c,d);
swap(e,f);
}

When this compiles, the compiler will see the first swap function call and determine that a swap function  is needed for integers.  Since it doesn't find one but does find the template, it will then generate the code for an integer swap function.  Likewise, on the following two lines it will do the same for a double swap and a string swap.   It will only generate code for templates when it is needed.

There is another nice aspect of using templates.  Say you wanted to swap (e,b) which is a string and an integer.  It won't let you do this because your template function header states that is is taking a T &a, and a T &b.  So the two types have to be the same.  Trying to do this would give you a compile time error.

But.. You can write a template to take more than one type.

Example:
template <class T, class S>
func(T &a, S &b)
{
     whatever code …
}
Note:      your symbols for the parameters can be any legal variable but T is by far the most common one used.

Let's go one step further and make an entire class into templates (List class) so we can use it for integers, doubles, strings, or CD's.

Standard List class

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

class List
{
     Node *head;

public:
     List();                         // constructor
     List(const List &);     // copy constructor
     List & operator =(const List &);
     ~List();
     ...
};



Template List class

template <class T>
struct Node
{
     T data;
     Node <T> *next;
};

template <class T>
class List
{
Node <T> *head

public:
List <T>();          
List <T>(const List <T> &);
List <T> & operator =(const List <T> &);
~List <T>();
int insert(const T&);
};

Now we have a template class definition which we can use for any type of data but we need to implement the functions...

_____________________________________________________________
template <class T>                                   // constructor
List <T>::List <T>()
{
     whatever you need to initialize
     head = 0;
}
______________________________________________________________
template <class T>
List <T>::List <T>(const List <T> &)     // copy constructor
{
     ...
}
_______________________________________________________________
template <class T>
int List <T>::insert(const T & value)
{
     ...
}

Notice that in the insert function you are just passing in a const T instead of List <T>  This may seem confusing at
first but remember that you are passing a data type such as a double or a string but you are using it in a template
so it is of class type T.  This is different than in the copy constructor where you are passing in a reference to a List.
In that case you need to say what type of List you are passing.  Hence the parameterized List<T>.

Important Note:     This won't compile in the C file like normal.  You must put all code for templates in the .h file including class definition, implementations, …


Now in your Test.C file…

#include "List.h"
...
...

main()
{
     List <int> list1;
  // when you get here, the compiler will break loose
     // and start to create a list class for integers but it will
     // only generate code for parts of the List class that
     // are needed in this program.

     List <string> list2;
     List <CD> list3;
     list1.insert(3);      // generates insert function for int now
     list2.insert("Hello");
     list3.insert(my_cd);

In each case, the compiler will generate a new function for each type of List but since it's a template, the compiler will do it for you automatically.  Now you can see how you can take advantage of the fact that you don't need to change any code.

How does this effect your Makefile?
You can't compile a template unless you have a particular type to compile.

test:test.o
     g++ -Wall -o test test.o

test.o:test.C List.h
     g++ -Wall -c test.C