You are on page 1of 7

If you were to look up the word template in the dictionary, youd find a definition that was similar to the

following: a template is a model that serves as a pattern for creating similar objects. Templates Exo-Static Polymorphism

Function templates
Template Functions are generalized functions where the compiler creates an instance of the function. To implement a program which has a template function write the template function, only the user has to do the prototype declaration of the function. template <class T> T sum (T x, T y) { return(x+y) } int main() { double sum (double,double); int sum(int,int); cout<<sum(3.5,3.6); cout<<sum(10,20); } While functions and classes are powerful and flexible tools for effective programming, in certain cases they can also be somewhat limiting because of C++s requirement that you specify the type of all parameters. Lets say you wanted to write a function to calculate the maximum of two numbers. You might do so like this:
int max(int nX, int nY) { return (nX > nY) ? nX : nY; }

What happens later when you realize your max() function needs to work with doubles? Traditionally, the answer would be to overload the max() function.
double max(double dX, double dY) { return (dX > dY) ? dX : dY; }

In C++, function templates are functions that serve as a pattern for creating other similar functions. The basic idea behind function templates is to create a function without having to specify the exact type(s) of some or all of the variables. Instead, we define the function using placeholder types, called template type parameters.
template <typename Type> // this is the template parameter declaration Type max(Type tX, Type tY) { return (tX > tY) ? tX : tY; }

If the template function uses multiple template type parameter, they can be separated by commas:
template <typename T1, typename T2> // template function here

Using function templates Using a function template is extremely straightforward you can use it just like any other function:
int nValue = max(3, 7); double dValue = max(6.34, 18.523); char chValue = max('a', '6'); // returns 7 // returns 18.523 // returns 'a'

Template functions do have a few drawbacks: 1. First, older compilers generally do not have very good template support. However, modern compilers are much better at supporting and implementing template functionality properly. 2. Second, template functions produce crazy-looking error messages that are much harder to decipher than those of regular functions. However, these drawbacks are fairly minor compared with the power and flexibility templates bring to your programming toolkit! Note: The standard library already comes with a templated max() function. If you use the statement using namespace std; the compiler will be unable to tell whether you want your version of max() or std::max().

Function template instances

C++ does not compile the template function directly. Instead, at compile time, when the compiler encounters a call to a template function, it replicates the template function and replaces the template type parameters with actual types! The function with actual types is called a function template instance. First, we have a templated function:
template <typename Type> // this is the template parameter declaration Type max(Type tX, Type tY) { return (tX > tY) ? tX : tY; } int nValue = max(3, 7); // calls max(int, int)

The compiler replicates the function template and creates the template instance max(int, int).
int max(int tX, int tY) { return (tX > tY) ? tX : tY; }

Now, lets say later in your code, you called max() again using a different type:
double dValue = max(6.34, 18.523); // calls max(double, double)

C++ automatically creates a template instance for max(double, double):


double max(double tX, double tY) { return (tX > tY) ? tX : tY; }

Operators, function calls, and function templates Template functions will work with both built-in types (eg. char, int, double, etc) and classes, with one caveat. When the compiler compiles the template instance, it compiles it just like a normal function. In a normal function, any operators or function calls that you use with your types must be defined, or you will get a compiler error. Similarly, any operators or function calls in your template function must be defined for any types the function template is instantiated for.

Template classes
We took a look at the IntArray class.
#ifndef INTARRAY_H #define INTARRAY_H

#include <assert.h> // for assert() class IntArray { private: int m_nLength; int *m_pnData; public: IntArray() { m_nLength = 0; m_pnData = 0; } IntArray(int nLength) { m_pnData = new int[nLength]; m_nLength = nLength; } ~IntArray() { delete[] m_pnData; } void Erase() { delete[] m_pnData; // We need to make sure we set m_pnData to 0 here, otherwise it will // be left pointing at deallocated memory! m_pnData = 0; m_nLength = 0; } int& operator[](int nIndex) { assert(nIndex >= 0 && nIndex < m_nLength); return m_pnData[nIndex]; } int GetLength() { return m_nLength; } };

What if we want to create an array of doubles? Using traditional programming methods, wed have to create an entirely new class!
#ifndef DOUBLEARRAY_H #define DOUBLEARRAY_H #include <assert.h> // for assert() class DoubleArray

{ private: int m_nLength; double *m_pdData; public: DoubleArray() { m_nLength = 0; m_pdData= 0; } DoubleArray(int nLength) { m_pdData= new double[nLength]; m_nLength = nLength; } ~DoubleArray() { delete[] m_pdData; } void Erase() { delete[] m_pdData; // We need to make sure we set m_pnData to 0 here, otherwise it will // be left pointing at deallocated memory! m_pdData= 0; m_nLength = 0; } double& operator[](int nIndex) { assert(nIndex >= 0 && nIndex < m_nLength); return m_pdData[nIndex]; } // The length of the array is always an integer // It does not depend on the data type of the array int GetLength() { return m_nLength; } }; #endif

This is another area where templates can be put to good use to free us from having to create classes that are bound to one specific data type. Heres the IntArray classes, templatated version:
#ifndef ARRAY_H #define ARRAY_H #include <assert.h> // for assert() template <typename T>

class Array { private: int m_nLength; T *m_ptData; public: Array() { m_nLength = 0; m_ptData = 0; } Array(int nLength) { m_ptData= new T[nLength]; m_nLength = nLength; } ~Array() { delete[] m_ptData; } void Erase() { delete[] m_ptData; // We need to make sure we set m_pnData to 0 here, otherwise it will // be left pointing at deallocated memory! m_ptData= 0; m_nLength = 0; } T& operator[](int nIndex) { assert(nIndex >= 0 && nIndex < m_nLength); return m_ptData[nIndex]; } // The length of the array is always an integer // It does not depend on the data type of the array int GetLength(); // templated GetLength() function defined below }; template <typename T> int Array<T>::GetLength() { return m_nLength; } #endif

Heres a short example using the above templated array class:


int main() { Array<int> anArray(12);

Array<double> adArray(12); for (int nCount = 0; nCount < 12; nCount++) { anArray[nCount] = nCount; adArray[nCount] = nCount + 0.5; } for (int nCount = 11; nCount >= 0; nCount----;) std::cout << anArray[nCount] << "\t" << adArray[nCount] << std::endl; return 0; }

A note for users using older compilers Some older compilers (eg. Visual Studio 6) have a bug where the definition of template class functions must be put in the same file as the template class is defined in. Thus, if the template class were defined in X.h, the function definitions would have to also go in X.h (not X.cpp). This issue should be fixed in most/all modern compilers.

You might also like