So what are templates good for? From what I've seen of examples of it online I guess it's good for being able to process a range of variables without needing to be specified, like it can take ints or doubles or chars instead of having to define several functions for each variable type that all do the same thing.
...
Also Reelya, all I can find of "c++ grid class" is webpages for the Stanford cslib package. So I guess if I wanted to use grid I'd need to download the cslib package and #include the header file? Or am I completely misunderstanding your example with the template and grid?
There is nothing to download because the full functionality for a 2D array is right there. "grid" is just the name I called my array class. call it array2D or anything you like. it's meant to be a complete set of working code, but I had one typo. Doublechecking what's allowed, and it's not allowed to have two parameters when overloading the [] operator. So that was my bad, and an error (fixable by changing the operator[] to operator(), which does allow multiple parameters).
You can either use ( x,y ) or [ x ][ y ] to access the array. Here's a working program illustrating using the (fixed) template class. I included both possible ways of indexing, but i recommend picking one style and deleting the unused operator. I have a feeling that the ( x , y ) version is slightly faster than the [ x ][ y ] version, since the [][] version casts the array address to a pointer, returns that to the calling code, then it gets dereferenced back to an actual variable.
#include <iostream>
using namespace std;
template <class T> class grid
{
T *data;
public:
int sizex, sizey;
grid(int _sizex, int _sizey) : sizex(_sizex), sizey(_sizey)
{
data = new T[sizex * sizey];
}
~grid() { delete [] data; }
T &operator()(int x, int y) { return data[x * sizey + y]; }
T *operator[](int x) { return &data[x * sizey]; }
};
int main()
{
grid<int> bob(20,20);
bob(1,1) = 30;
bob[2][2] = 25;
cout << bob(1,1) << endl;
cout << bob(2,2) << endl;
cout << bob[1][1] << endl;
cout << bob[2][2] << endl;
while(1==1);
return 0;
}
There are several advantage of templates. For the "grid" object, since they're objects, you can pass them into functions as parameters and they remember their size. And when the object is destroyed, they remember to delete the data.
For templates in general some advantages of using them are:
- reuse template classes in new projects without needing changes
- improve your templates over multiple projects, so any problem with the template adds to your library
- turn project-specific code into a template class, then you can more easily extract general functionality
- template classes don't need to #include the header file of class that they are using. which reduces chains of header file dependencies and speeds up recompiles.
- since templates don't know anything about the objects they're manipulating, it's harder to break them by changing the objects
- templates are resolved at compile time, meaning more errors picked up before runtime
- templates provide static polymorphism instead of dynamic polymorphism, which could be faster.
- templates can pre-calculate any value since c++'s template system is turing-complete. as long your values are known at compile time, you can do arbitrarily complex caculations in zero runtime.
One thing I really like about templates is the possibility to provide polymorphism but without the different objects needing to be part of an inheritance tree. So no worry about virtual functions etc, just add in the single needed method in any class you pass into the template. The compile will tell you if you're missing the needed method.
Here's an example using a template function instead of a class:
#include <iostream>
using namespace std;
template <class T> void draw(T thing)
{
thing.draw();
};
class drawableThing
{
public:
void draw() { cout << "I'm being drawn!\n"; };
};
class differentDrawableThing
{
public:
void draw() { cout << "Put me on the screen!\n"; };
};
int main()
{
drawableThing thing;
draw(thing);
differentDrawableThing otherThing;
draw(otherThing);
while(1==1);
return 0;
}
This is an example of compile-time polymorphism, which generally runs faster and doesn't require you to have inheritance trees.