It must start with the keyword templatefollowed by the template parameter list for the
class.
It must indicate the class of which it is a member.
The class name must include its template parameters.
From these rules, we can see that a member function of class Queuedefined outside the class will
start as
template <class T> ret-typeQueue<T>::member-name
The destroy Function
To illustrate a class template member function defined outside its class, let's look at the destroy
function:
template <class Type> void Queue<Type>::destroy()
{
while (!empty())
pop();
}
The pop Function
template <class Type> void Queue<Type>::pop()
{
// pop is unchecked: Popping off an empty Queue is undefined
QueueItem<Type>* p = head; // keep pointer to head so we can delete it
head = head->next; // head now points to next element
delete p; // delete old head element
}
The push Function
The pushmember places a new item at the back of the queue:
template <class Type> void Queue<Type>::push(const Type &val)
{
// allocate a new QueueItem object
QueueItem<Type> *pt = new QueueItem<Type>(val);
// put item onto existing queue
if (empty())
head = tail = pt; // the queue now has only one element
else {
tail->next = pt; // add new element to end of the queue
tail = pt;
}
}
The copy Function
template <class Type>
void Queue<Type>::copy_elems(const Queue &orig)
{
// copy elements from orig into this Queue
// loop stops when pt == 0, which happens when we reach orig.tail
for (QueueItem<Type> *pt = orig.head; pt; pt = pt->next)
push(pt->item); // copy the element
}
Instantiation of Class-Template Member Functions
Member functions of class templates are themselves function templates. Like any other function template, a member function of a class template is used to generate instantiations of that member. Unlike other function templates, the compiler does not perform template-argument deduction when instantiating class template member functions. Instead, the template parameters of a class template member function are determined by the type of the object on which the call is made. For example, when we call the pushmember of an object of type Queue<int>, the push function that is instantiated is
void Queue<int>::push(const int &val)
The fact that member-function template parameters are fixed by the template arguments of the object means that calling a class template member function is more flexible than comparable calls to function templates. Normal conversions are allowed on arguments to function parameters that were defined using the template parameter:
Queue<int> qi; // instantiates class Queue<int>
short s = 42;
int i = 42;
// ok: s converted to int and passed to push
qi.push(s); // instantiates Queue<int>::push(const int&)
qi.push(i); // uses Queue<int>::push(const int&)
f(s); // instantiates f(const short&)
f(i); // instantiates f(const int&)
When Classes and Members Are Instantiated
Member functions of a class template are instantiated only for functions that are used by the program. If a function is never used, then that member function is never instantiated. This behavior implies that types used to instantiate a template need to meet only the requirements of the operations that are actually used.
When we define an object of a template type, that definition causes the class template to be instantiated. Defining an object also instantiates whichever constructor was used to initialize the object, along with any members called by that constructor:
// instantiates Queue<int> class and Queue<int>::Queue()
Queue<string> qs;
qs.push("hello"); // instantiates Queue<int>::push
The QueueItemmembers in Queueare pointers.Defining a pointer to a class template doesn't instantiate the class; the class is instantiated only when we use such a pointer. Thus, QueueItemis not instantiated when we create a Queueobject. Instead, the QueueItemclass is instanatiated when a Queuemember such as front, push, or popis used.