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
}