Advanced Templates
Templates with Multiple Type Parameters
A class template may have more than one type parameter.
The template below defines a class that encapsulates pairs
of objects -- the first is the key, the second is the data.
Templates can have Nontype Parameters
Not all of the parameters for a template need be class type
parameters.  For instance, we could have written the SmartArray
template to include the size as a nontype template parameter
as shown below.  This technique avoids the necessity of using 
dynamically allocated memory for the SmartArray class.
template 
class SmartArray 
{
   public:
      SmartArray ( );
      // other members
   private:
      int m_size;
      T m_data[ size ];
};
template< class T, int size>
SmartArray::SmartArray( )
{
    m_size = size;
}
Templates as Parameters
When we wish to pass a template class to a function, that function becomes
a function template.  Here's the definition for a function that sorts
the elements of a smart arrary.  We want to use it for all types of
smart arrays, so we pass the smart array template as the parameter.
template 
void Sort ( SmartArray& theArray)
{
   // code here
}
Templates and Friends
We can make functions friends of templates too.  For example, if we want to output
SmartArrays using operator<<, we define the function as a template
as above
template 
ostream& operator<< (ostream& out, const SmartArray& theArray)
{
  // code here
}
In the SmartArray class definition we declare operator<< to be our friend in the usual way, but we must tell the compiler that operator<<
is a template function.  One easy way to do this by including "<>" after the
name of the function.
template 
class SmartArray
{
      friend ostream& operator<< <> (ostream& out, const SmartArray& theArray);
  // the rest of the SmartArray class definition
};
There is one other key component to completing your implementation of a
templated friend in your application, in order to allow the compiler to
understand where the operator belongs and which class it belongs to.  We use a
technique called "forward declaring" in order to notify the compiler of each
of these components.  Essentially "forward declaring" is prototyping everything
that you will be declaring:
template  class FooClass; // forward-declaring class 
template  ostream& operator<< (ostream& out, const FooClass &foo); // forward-declaring insertion stream 
template  
class FooClass 
{ 
   public: 
      friend ostream& operator<< <> (ostream& out, const FooClass &foo); 
   private: 
}; 
template  
ostream& operator<< (ostream& out, const FooClass &foo)
{
   // implementation
}