7.3 Variable and Constant Template Parameters
Template parameters may be variables or constant values, including a constant class name. When a variable is used as a template parameter, a value for the variable must be supplied when the template is elaborated. A template may also have both a class parameter and a variable parameter. A constant template parameter is used to define special-case templates, which are often used in conjunction with a general template to define a special variant of the general template. A special variant is often needed because there are a few cases in which the assumptions made by the general template are not appropriate and an alternative template is needed. Both of these kinds of template parameters are described in this section.
A variable as a template parameter is shown in the following redefinition of the Queue template. Notice that the template has two parameters: QueueItem defines the type of the elements maintained by the queue, and size defines the maximum number of elements that can be in the queue at any one time.
Both template parameters are used in the declaration of the buffer array
where 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.
Notice that the size parameter is used whenever the array length is needed. Thus, instead of head=(head+1)%100; being used to adjust the index of the head of the queue, the code 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 may 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 previously seen that instantiating the template with 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 to each other while objects of different types cannot. This is illustrated by the following code:
intQueue1 = intQueue2; // OK, queues of the same type intQueue1 = realQueue; // ERROR - queues of incompatible type realQueue = intQueue2; // ERROR - queues of incompatible type
The type compatiblilty of objects created by templates with multiple parameters is similar: two template elaborations are the same if and only if they are elaborated with the same parameters. This means that any class parameters must be the same and any variable parameters must have the same value. Here, these rules are illustrated using the modified (two parameter) Queue template:
Queue<int, 100> largeIntegerQueue1; Queue<int, 100> largeIntegerQueue2; Queue<int, 10> smallIntegerQueue; Queue<float, 100> largeRealQueue; largeIntegerQueue1 = largeIntegerQueue2; // OK, queues of the same type largeIntegerQueue1 = largeRealQueue; // ERROR - queues of incompatible type largeIntegerQueue1 = smallIntegerQueue; // ERROR - queues of incompatible type
The first assignment is between compatible types - both the QueueItem type (int) and the size value (100) are the same. However, the second two assignments 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 because the size parameter is different (100 vs. 10), although the QueueItem parameter is the same.
There may be certain classes that cannot be used to elaborate a general template because the class does not satisfy the assumptions made by the template about the class given as its parameter. It was seen earlier that the Displayable template made assumptions about its parameterizing class. A portion of the definition of the Displayable template is repeated below for reference.
The important thing is that the Displayable template assumes that the instantiating class has methods ToString and FromString that convert between the class's 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:
Displayable<int> intDisplay; Displayable<float> realDisplay; Displayable<Location> locationDisplay;
will not work because none of these built-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.
A "special case" version of the Displayable template can be defined for ints as shown below. Notice that the template parameter is a fixed (or constant) type: namely the built-in type int. This template provides the special-case definitions of the ToString and FromString methods that are needed by the template but which are lacking in the int type.