Templates

Template Functions

A template function is used to write a function in which the type of one or more of the arguments is not yet known when we write the code.

The syntax for this is:

     template <class T>
     function definition;

where T is the name of a class or a struct or perhaps one of the elementary types.

Example: Here is a function to return the larger of two values.

     template <class T>
     T Larger(const T & X, const T & Y)
     {
      if (X > Y)
       return X;
      else 
       return Y;
     }

Notice that this will make sense only if operator > makes sense for type T.

To use this, we simply call Larger with two arguments of the same type, as in:

     cout << Larger(c1, c2);

where c1 and c2 are of type char

or

     cout << Larger(N1, N2);

where N1 and N2 are of type int.

Example: We could have a template function to add the values in an array of T, returning the sum.

     template <class T>
     T Sum(T [] A, const int & Size)
     {
      T Temp = 0;
      for (int I = 0; I < Size; I++)
       T += A[I];
      return Temp;
     }

This will make sense only if it makes sense to say Temp = 0 and to use operator += for T.


Template Classes

We can also have template classes.

The syntax for this is:

     template <class T>
     class definition;

where T is the name of a class or a struct or perhaps one of the elementary types.

Example: Here is a dynamically-sized array class.

     template <class T>
     class DArray
     {
      private:
       T * A;
       int Size;
      public:
       DArray();                           // initialize Size = 0 
       ~DArray();                          // delete the array
       T operator [](const int & N) const; // for B = A[3];
       T & operator [](const int & N);     // for A[3] = B;
       // (possibly many more)
      };

To use this to make a dynamic array of int:

     DArray<int> IntList;

To make a dynamic array of float:

     DArray<float> FloatList;

These are called instantiations of DArray.

When we write the code for a template class, each method is a template function:

template <class T>
DArray<T>::DArray()
{
...
}

For a template class, the code is included in the header file as well as the class definition. It cannot be compiled until it is instantiated.


Templates with more than one argument

A template class or function can have more than one argument, as in:

     template <class T, int Size>
     class List
     {
      private:
       T A[Size];
      ... 
     };
and we could instantiate it:
     List<float, 25> Q;
which makes Q an instance of List in which we have an array of 25 floats.


Friends of Template Classes

Sometimes we are inventing a template class and we need to have a friend of that class. In that case, the friend function will have to be a template function. This situation requires a bit of extra care.

For example, suppose we have:

     template <class T>
     class Gizmo
     {
      ...
     };

and we would like for a function called DoIt to be a friend of the Gizmo<T> class. We could add a line such as

     friend void DoIt(Gizmo<T> &);

to the class definition, but this will not quite work.

Instead, we need to make it more explicit that this is a template function. We can add the following to the class definition:

     template <class S>
     friend void DoIt(Gizmo<S>);

and then when we write the code for DoIt, we have:

     template <class S>
     friend void DoIt(Gizmo<S> Name;)
     {
     ...
     }

Here is an example for the DArray class above.

In the class definition, we need to have:

     template <class S>
     friend ostream & operator<<(ostream &, const Queue< S> &);

and likewise, when we write the code, we will use this heading:

     template <class S>
     ostream & operator <<(ostream & Os, const Queue<S> & Q)

and then write the code using S instead of T.