Template Classes and Functions

Function Templates

This is a slick trick for defining a function that is more versatile, and can perform its work on items of more than one type. Arithmetic operations are good examples.
The idea of a function template is to write a function that performs an algorithm that may be the same for different related types, but to allow the function to fill in the exact type later.

Example: We could define a function that computes the maximum of three different numbers like this.

  int maximum(int a, int b, int c)
  { 
     int max = a;
     if (b > max)
	max = b;
     if (c > max)
	max = c;
     return max;
  }
However, this only works for int variables (or types that can be automatically converted, like shorts). But what if we wanted to compare double variables? Do we have to write a new function?

A template function allows this problem to be solved easily, with only one function (that will fit any of the basic types -- whether char, short, int, double, etc).

Templated version of maximum
 

Another Example

This is a function that prints the contents of an array, the items separated by spaces.
 template< class T >
 void printArray( const T *array, const int count )
 {
   for ( int i = 0; i < count; i++ )
      cout << array[ i ] << " ";

   cout << endl;
 } 

Notice that this function will work on arrays of any of the basic built-in types.  It will also work for any class type for which an appropriate insertion operator << has been defined (since this is used in the function definition).

A copy of this example, along with a sample main program, can be found here.

In addition to creating template versions of functions, we can do a similar thing with classes.


Making container classes versatile

It is often useful to build a class that allows for storage of many related data items, possibly large amounts of data.  Here is an example of a small class that uses array-based storage to maintain a small list of integer values.

SimpleList Example 1

Now, suppose we sometimes want to have a class that can store a list of double values.   Or perhaps a list of characters.  We could write another similar class for each of these, along with separate classes for each new type, but that would be tedious.  It would be nice if this class could provide the ability to vary the type of data stored.

A common C trick is to use a typedef.  This is a reserved word that allows the creation of a simple user-defined type, usually as an alias name for another type.  Here is an example that uses a typedef to make the class more versatile.

SimpleList Example 2

In this example, we see the following statement preceding the class definition:

 typedef int mytype;

Notice that in this statement, the user-defined type mytype simply becomes a synonym for the type int.  Also notice that the word mytype is now used in place of int in the places that represent the stored values.  We can change this class to represent a list of type double, for example, simply by changing the one line at the top to:

 typedef double mytype;

No other changes are needed in the code, as the word mytype now becomes a synonym for double.  Of course, to accomplish this, we must alter one line of code and re-compile.  This is the drawback to the typedef trick.
 

Class Templates

With class templates, we can make this class work with a variety of types, without resorting to altering and recompiling code.  The class template will work in a similar manner to the function template.  Here is an example of the SimpleList class written as a template:

SimpleList Example 3

To make a class into a template, prefix the class definition with the syntax:

 template< class T >

T in the above line is just a type parameter, and it can have any name.  Like a function parameter, it is a placeholder.  When the class is instantiated, we fill in an appropriate type. Use this prefix also on the definitions of member functions, and the name of the class used in context with the scope resolution operator will be:

 className< T >::memberName

Notice that in this SimpleList example, the type of the array is T -- the type parameter -- and this will be filled in when an object is created.  Examples of this are in the sample main program that is included.

Also notice that in the main program, we must #include the actual definition file -- all the template function definitions, in addition to the class definition. This is because the compiler creates a different version of the class for each type that is used when building objects. This means that either the entire class should be written in the header file, OR that the .cpp file should be #included, like this:

 #include "simplelist3.cpp"


The following is an example of a more complicated class that uses array-based storage (dynamic) to maintain a list of items. This is a class template, so the type of item stored in the list can vary from object to object:   List Example


Examples from textbook (Savitch)