Saturday, January 10, 2009

C++ Templates -- Part 1

Before starting on what are templates lets understand why templates are required or what they can do. Suppose you are creating a dynamic array of some objects which will update it’s size as an when you add or remove elements.

class SmartIntArray
{
int* arr;
size_t num_elems;
public:
SmartIntArray() : arr(NULL), num_elems(0)
{}
SmartIntArray(size_t elements) : arr(NULL), num_elems(0)
{
this->arr = new int[elements];
this->num_elems = elements;
}

void Clear()
{
delete this->arr;
this->arr = NULL;
this->num_elems = 0;
}

~SmartIntArray()
{
this->Clear();
}
};



Overall this class serves it purpose.



now if you want to have a dynamic array of doubles, quite simple copy and paste replace int by double at appropriate places!




class SmartDoubleArray
{
double* arr;
size_t num_elems;
public:
SmartDoubleArray() : arr(NULL), num_elems(0)
{}
SmartDoubleArray(size_t elements) : arr(NULL), num_elems(0)
{
this->arr = new double[elements];
this->num_elems = elements;
}

void Clear()
{
delete this->arr;
this->arr = NULL;
this->num_elems = 0;
}

~SmartDoubleArray()
{
this->Clear();
}
};




What about char, short etc…



there are several ways one can address this:




  1. Instead of int* or double* keep void* and cast appropriately. Casting is the responsibility of the caller and the smart array is not so smart any more


  2. Copy code all the time and replace names appropriately. This usually works but has suffers from copy-paste syndrome. SmartIntArray has an undefined behaviour and same has been passed to SmartDoubleArray


  3. Identify genericity and use generic/parametric code. This is where C++ Templates comes into picture



Here is the C++ Template for the SmartArray class




template<class Type>
class SmartArray
{
Type* arr;
size_t num_elems;
public:
SmartArray() : arr(NULL), num_elems(0)
{}
SmartArray(size_t elements) : arr(NULL), num_elems(0)
{
this->arr = new Type[elements];
this->num_elems = elements;
}

void Clear()
{
delete[] this->arr;
this->arr = NULL;
this->num_elems = 0;
}

~SmartArray()
{
this->Clear();
}
};



If you notice the Clear method was not deleting the array of elements, missing array indexers. Fixing this would have required to make changes in SmartIntArray and SmartDoubleArray and what not. And if these are headers then all the files that make use of these SmartArray class would have to be recompiled!


With templates SmartIntArray and SmartDoubleArray classes can be redefined as



typedef SmartArray<int> SmartIntArray;
typedef SmartArray<double> SmartDoubleArray;



Things to look in this class are:


template keyword declares following construct either function or class/struct to be serve as a template for some generic code. It requires you to pass in the parameter/type on which the code will be generalized, in this case it is Type



template<class Type>
class SmartArray
{


/* For SmartArray of int Type in the above declaration is replaced by int. Thus Type* arr is converted to int* arr; */



    Type* arr;
size_t num_elems;
public:
SmartArray(size_t elements) : arr(NULL), num_elems(0)
{


/* Similarly here the Type is replaced by int this is equivalent to this->arr = new int[elements]; */


        this->arr = new Type[elements];
this->num_elems = elements;
}
};

I think this is good enough to start off. Will post more on how to templatize classes and functions and their funky rules!


Till then have fun...

No comments: