Function templates empower us to create multiple functions in which the code is the same, but the data handled is of different types. A function template simplifies the process of overloading functions by keeping us from having to repeat the same code over and over for different parameters.
A function template is defined using the keyword template. We use a placeholder, typically the letter T, for the type of data we want the function to operate on.
#include <iostream>
template <class Type>
Type larger(Type x, Type y);
using namespace std;
int main(void){
int iValue = 8088;
int iValue2 = 404;
double dValue = 62.324;
double dValue2 = 917.7;
cout << "The larger of " << iValue;
cout << " and " << iValue2 << " is ";
cout << larger(iValue, iValue2) << endl;
cout << "The larger of " << dValue;
cout << " and " << dValue2 << " is ";
cout << larger(dValue, dValue2) << endl;
return 0;
}
template <class Type>
Type larger(Type x, Type y){
if(x >= y){
return x;
} else {
return y;
}
}
Note that the angle brackets are necessary.
Programmers typically use a capital T to denote the placeholder, which we will now do as well. This is the same style used in declaring generic methods in C# and Java, with virtually the same syntax as well. Both of those languages “grew” out of C++, which is one of the reasons I think C++ and C are so relevant, at least in terms of learning how to code. C# makes a lot more sense in the light of C++ than it does on its own, I think.
When we use a code template, the C++ compiler will instantiate the correct version of the function, depending on the arguments passed to it.
#include <iostream>
template <class T>
T square(T data);
template <class T>
void printSquare(T data);
using namespace std;
int main(void){
int iValue = 16;
cout << iValue << " squared is " << square(iValue) << endl;
printSquare(14.571);
printSquare(42);
return 0;
}
template <class T>
T square(T data){
return data * data;
}
template <class T>
void printSquare(T data){
cout << data << "^2 = " << square(data) << endl;
}
As we have seen, a function template defines a function in terms of an arbitrary type for which a specific type can be substituted. Since types are represented by parameters, we sometimes refer to this template feature as parameterized types. The template is not a function itself, rather it is a blueprint that enables the compiler to create functions.
Of course, it’s possible to specify a template that takes more than one type of data. In the following example, we will define a function called Add() that will take data of two different types, and return a value of the type of the first parameter.
#include <iostream>
template <class ReturnType, class OtherType>
ReturnType Add(ReturnType x, OtherType y);
using namespace std;
int main(void){
int iX = 14;
double dY = 17.99;
cout << iX << " + " << dY << " = ";
cout << Add(iX, dY) << endl;
cout << dY << " + " << iX << " = ";
cout << Add(dY, iX) << endl;
return 0;
}
template <class ReturnType, class OtherType>
ReturnType Add(ReturnType x, OtherType y){
return x + (ReturnType)y;
}
We can overload templates in the same way that we overload regular function definitions. Just as with regular overloading, template overloading requires distinct function signatures in order to work.
#include <iostream>
template <class TOne, class TTwo>
void CopyArray(TOne arrParamOne[], TTwo arrParamTwo, int bounds);
template <class T>
void CopyArray(T arrParamOne[], T arrParamTwo, int bounds);
template <class T>
void PrintArray(T arrParam, int bounds);
using namespace std;
int main(void){
double dArray[] = {2.718, 0.57721, 3.14159, 1.61803, 15.3465111};
double dArrayTwo[5];
int iArray[] = {73, 2600, 404, 6174, 8086};
PrintArray(iArray, 5);
CopyArray(dArrayTwo, dArray, 5);
PrintArray(dArrayTwo, 5);
CopyArray(iArray, dArrayTwo, 5);
PrintArray(iArray, 5);
return 0;
}
template <class TOne, class TTwo>
void CopyArray(TOne arrParamOne[], TTwo arrParamTwo, int bounds){
for(int i = 0 ; i < bounds; i++){
arrParamOne[i] = (TOne)arrParamTwo[i];
}
}
template <class T>
void CopyArray(T arrParamOne[], T arrParamTwo, int bounds){
for(int i = 0; i < bounds; i++){
arrParamOne[i] = arrParamTwo[i];
}
}
template <class T>
void PrintArray(T arrParam, int bounds){
for(int i = 0; i < bounds; i++){
cout << arrParam[i] << " ";
}
cout << endl;
}
We use templates when we need functions that use the same basic algorithm with a variety of types.