Wrox Press C++ Tutorial
The last example was somewhat tedious in that we had to repeat essentially the same code for each function, but with different variable and parameter types. However, we also have the possibility of having a recipe for automatically generating functions of various types. The code to do this for a particular group of functions is called a function template.
The functions generated by a function template all have the same basic code, but have one or more types defined as parameters to the template. As you use a particular form of a template function, a version is automatically generated to support the type of arguments that you use. We can demonstrate this by defining a function template for the function max() in the previous example.
We can define a template for the function max() as follows:
template<class T> T max(T x[], int len)
{
T max = x[0];
for(int i=1; i<len; i++)
if(max<x[i])
max = x[i];
return max;
}
The template keyword identifies this as a template definition. The angled brackets following the template keyword enclose the type parameters that are used to create a particular instance of the function. The keyword class before the T indicates that the T is the type parameter for this template, class being the generic term for type. We shall see later in the book that defining a class is essentially defining your own data type. Consequently, you have basic types in C++, such as int and char, and you also have the types that you define yourself.
Wherever T appears in the definition of the template, it is to be replaced by a specific type, such as long, when an instance of the template is created. If you try this out manually, you'll see that this will generate a perfectly satisfactory function for calculating the maximum value from an array of type long. The creation of a particular function instance is referred to as instantiation. In our case, we have just one type parameter, T, but in general, there can be more.
Each time you use the function max() in your program, the compiler will check to see if a function corresponding to the type of arguments that you have used in the function call already exists. If the required function does not exist, the compiler will create one by substituting the argument type that you have used in place of the parameter T throughout the source code in the template definition. You could exercise this template with the same function main() that we used in the previous example:
// Ex5_07.cpp
// Using function templates
#include <iostream>
using namespace std;
// Template for function to compute the
// maximum element of an array
template<class T> T max(T x[], int len)
{
T max = x[0];
for(int i=1; i<len; i++)
if(max<x[i])
max = x[i];
return max;
}
int main()
{
int small[] = { 1,24,34,22};
long medium[] = { 23,245,123,1,234,2345};
double large[] = { 23.0,1.4,2.456,345.5,12.0, 21.0};
int lensmall = sizeof small/sizeof small[0];
int lenmedium = sizeof medium/sizeof medium[0];
int lenlarge = sizeof large/sizeof large[0];
cout << endl << max(small, lensmall);
cout << endl << max(medium, lenmedium);
cout << endl << max(large, lenlarge);
cout << endl;
return 0;
}
If you run this program, it will produce exactly the same output as the previous example. For each of the statements outputting the maximum value in an array, a new version of max() is instantiated using the template. Of course, if you add another statement calling the function max() with one of the types used previously, no new version of the code is generated.
Note that using a template doesn't reduce the size of your compiled program in any way. A version of the source code is generated for each function that you require. In fact, using templates can generally increase the size of your program, as functions can be created automatically even though an existing version might satisfactorily be used by casting the argument accordingly. You can force the creation of particular instances of a template by explicitly including a declaration for it. For example, if you wanted to ensure that an instance of the template for the function max() was created corresponding to the type float, you could place the following declaration after the definition of the template:
float max(float, int);
This will force the creation of this version of the function template. It does not have much value in the case of our program example; but it can be useful when you know that several versions of a template function might be generated, but you want to force the generation of a subset that you plan to use with arguments cast to the appropriate type where necessary.