template <class QueueItem, int size> class Queue { private: QueueItem buffer[size]; int head, tail, count; public: Queue(); void Insert(QueueItem item); QueueItem Remove(); int Size(); ~Queue(); };Both template parameters are used in the declaration of the buffer array:
QueueItem buffer[size];QueueItem defines the base type of the array and size defines the length of the array. The size template parameter is used in the code for the template as shown below. Notice that the full list of template arguments must be given at numerous places in the definition.
template <class QueueItem, int size> Queue<QueueItem,size>::Queue() : count(0), head(0), tail(0) {} template <class QueueItem, int size> void Queue<QueueItem, size>::Insert(QueueItem item) { assert(count <size); buffer[tail] = item; tail = (tail + 1)% size; count++; } template <class QueueItem, size> QueueItem Queue<QueueItem, size>::Remove() { assert(count > 0); int val = head; head = (head + 1)%size; count--; return buffer[val]; } template <class QueueItem, int size> int Queue<QueueItem, size>::Size() { return count; } template <class QueueItem, int size> Queue<QueueItem, size>::~Queue() {}Notice that the size parameter is used whenever the array length is needed. Thus instead of "head = (head + 1) % 100;" the code now uses the template variable size to refer to the length of the buffer as in "head = (head + 1) % size;".
Queues of various types and size can be declared and used as follows:
Queue<int,100> smallIntegerQueue; Queue<int, 1000> largeIntegerQueue; Queue<float, 100> smallRealQueue; Queue<float, 1000> largeRealQueue; smallIntegerQueue.Add(10); largeIntegerQueue.Add(20); smallRealQueue.Add(1.4159); largeRealQueue.Add(0.123);The type of an object created via a template depends on all of the template's parameters. It was previous seen that instantiating the template different types created objects of different types. Thus, using the previous declaration of the queue template:
Queue<int> intQueue1; Queue<int> intQueue2; Queue<float> realQueue;created objects of two different types. As usual, objects of the same type can be assigned while objects of different types cannot. This is shown in the following code:
intQueue1 = intQueue2; // OK, queues of the same type intQueue1 = realQueue; // ERROR - queues of incompatible type realQueue = intQueue2; // ERROR - queues of incompatible typeThe type compatiblilty of object created by templates with multiple parameters is similar: two template instantiations are the same if and only if they are instantiated with the same parameters. This means that any class parameters must be the same and any variable paramters must have the same value. These rules are illustrated in the following code using the modified (two parameter) Queue template:
QueueThe first assignment is between compatible types - both the QueueItem type (int) and the size value (100) are the same. However, the second two assignment are in error. The first error occurs because the QueueItem parameters do not agree (int vs. float) although the size parameter is the same (100). The second error occurs becasue the size parameter is different (100 vs. 10) although the QueueItem parameter is the same.largeIntegerQueue1; Queue largeIntegerQueue2; Queue smallIntegerQueue; Queue largeRealQueue; largeIntegerQueue1 = largeIntegerQueue2; // OK, queues of the same type largeIntegerQueue1 = largeRealQueue; // ERROR - queues of incompatible type largeIntegerQueue1 = smallIntegerQueue; // ERROR - queues of incompatible type
template <class T> class Displayable { private: T* displayed; TextBox* textBox; public: Displayable(TextBox* tbox); // testbox to show in void ShowThis(T* d); // what to show void Show(); // show current value void Reset(); // reset displayed from textBox ~Displayable(); }; ... template <class T> Displayable<T>::Show() { textBox->SetText(displayed->ToString()); } template <class T> Displayable<T>::Reset() { displayed->FromString(textBox->GetText()); }The important thing to notice is that the Displayable template assumes that the instantiating class has methods ToString and FromString that convert between the class' internal representation of its value and an external string representation.
Certain obvious uses of the Displayable template will not work because the instantiating class (or type) does not have the methods required by the template. For example:
DisplayableWill not work because none of these build-in types has the methods required by the Displayable template. While it might be possible to add the required methods to the Location class, it is not possible to do this for the built-in types int and float.intDisplay; Displayable realDisplay; Displayable locationDisplay;
A "special case" version of the Displayable template can be defined for ints as follows:
class Displayable{ private: int* displayed; TextBox* textBox; char* ToString(int v); int FromString(char* text); public: Displayable(TextBox* tbox); // testbox to show in void ShowThis(int* d); // what to show void Show(); // show current value void Reset(); // reset displayed from textBox ~Displayable(); }; char* Displayable ::ToString(int v) { char* buf = new char[10]; sprintf(buf, "%d", v); return buf; } int Displayable ::FromString(char* text) { return atoi(text); } Displayable ::Displayable(TextBox *tbox) {textBox = tbox; displayed = (int*)0;} void Displayable ::ShowThis(int* d) { displayed = d; } void Displayable ::Show() { textBox->SetText(ToString(*displayed)); } void Displayable ::Reset() { *displayed = FromString(textBox->GetText()); } Displayable ::~Displayable(){}