Templates
Topics
1. Introduction
Templates allow us to write functions and classes that are based on parameterized types. For example, we may wish to write a function or class to run quicksort on (1) an array of ints and (2) an array of floats. Rather than writing two separate versions, one for ints and one for floats, we may write a single generic template from which the compiler can generate the int and float versions of quicksort.
2. Function Templates
The following example illustrates how to use function templates.
FunctionTemplates.cpp
#include <iostream.h>
// A function template for creating functions that reverse the order of the elements in an array.
template<typename ItemType>
void reverse(ItemType a[], int N) {
for (int i = 0; i < N/2; i++) {
ItemType tmp = a[i];
a[i] = a[N-1-i];
a[N-1-i] = tmp;
}
}
// A function template, where the type cannot be inferred from the function arguments.
template<typename ItemType>
void print(void *p, int N) {
ItemType *a = (ItemType *)p;
for (int i = 0; i < N; i++)
cout << "Element " << i << " is " << a[i] << endl;
}
// Optional: you are allowed to explicitly instantiate the function templates, if you wish. If you don't
// do this, the instantiation will occur implicitly as a result of the functions calls below.
template void print<int>(void *, int);
template void print<float>(void *, int);
const int aLength = 5;
const int bLength = 10;
int main() {
int i;
int a[aLength];
float b[bLength];
for (i = 0; i < aLength; i++)
a[i] = i;
for (i = 0; i < bLength; i++)
b[i] = (float)i;
// The compiler will create two versions of reverse(), one to handle ints and one to handle floats.
// In this case, ItemType can be inferred from the first argument.
reverse(a, aLength);
reverse(b, bLength);
// The compiler will create two versions of print(), one to handle ints and one to handle floats.
// In this case, ItemType cannot be inferred from the function arguments. Hence, explicit
// specification of the parameter is required. (VC++ users note: VC++ 6.0 has a bug which
// causes it to use the float version in both cases.)
print<int>((void *)a, aLength);
print<float>((void *)b, bLength);
return 0;
}
3. Class Templates
The following example illustrates how to use class templates.
ArrayClass.h
#include <iostream.h>
// This class template allows us to create array objects of any type and size.
template<typename ItemType, int size>
class ArrayClass {
private:
ItemType array[size];
public:
ArrayClass();
~ArrayClass() {}
void print();
};
// In a class template, all member function definitions should be placed in the header file.
template<typename ItemType, int size>
ArrayClass<ItemType, size>::ArrayClass() {
for (int i = 0; i < size; i++) {
array[i] = (ItemType)(i/2.0); // The chosen default behavior.
}
}
template<typename ItemType, int size>
void ArrayClass<ItemType, size>::print() {
for (int i = 0; i < size; i++) {
cout << array[i] << endl;
}
}
Main.cpp
#include "ArrayClass.h"
int main() {
ArrayClass<int, 5> a;
ArrayClass<float, 10> b;
a.print();
cout << endl;
b.print();
return 0;
}