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. <!--#include virtual="Pairs.cpp"-->

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 T, int size> class SmartArray { public: SmartArray ( ); // other members private: int m_size; T m_data[ size ]; }; template< class T, int size> SmartArray<T, size>::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 <class T> void Sort ( SmartArray<T>& 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 <class T> ostream& operator<< (ostream& out, const SmartArray<T>& 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 T> class SmartArray { friend ostream& operator<< <> (ostream& out, const SmartArray<T>& 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 T> class FooClass; // forward-declaring class template <class T> ostream& operator<< (ostream& out, const FooClass &foo); // forward-declaring insertion stream template <class T> class FooClass { public: friend ostream& operator<< <> (ostream& out, const FooClass &foo); private: }; template <class T> ostream& operator<< (ostream& out, const FooClass &foo) { // implementation }