template

Function Templates in C++

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.