wtf is a template ?

Started by
15 comments, last by Endemoniada 20 years, 5 months ago
there are two extremely basic and usefull example of the power of template - and what they are for:

template functions

ex 1 - the swap function - as given by blizard999 - see how the function is "templated" on it''s parameter types ... which means that the compiler will create different versions of the function, for each set of types the program actual calls it with ... so EACH CALL can be perfectly efficient, using the exact correct amount of memory, and no extra instructions or parameters to pass in the amount of data to swap ... all this is done by the compiler, at compile time ..

template classes

ex 2 - a generic "container" class, such as the stl "list" class. these classes usually are templated based on their element types, and used like this:

list registeredStudents;

which would create a linked list classes, specifically for the Student data type, with the same types of advantages / optimizations as the swap function - everything would automatically be the right size, and to correct functions would be called for the copy constructor, etc ...

this stuff is just so powerfull when you really learn to use it without having to think about it too hard ...

when you are used to langauge without it, like Java, or old C++, it takes a while to really start getting it, but when you do, the old method, with linked list classes written for "Object"s and all the run-time dynamic casting to the correct types ... etc ... it just sucks ... template programming is the next step beyond just using OO programming ... and provides enourmous gains in developer productivity ... for example ... look up the "map" class ... it is a general purpose dictionary (also called hash or associative array) class - and can do so many things when used correctly -

here''s an example ... say you need to keep a list of students and their registered classes ... for a quick prototype (until you have the time to wrap the stuff in a class with the perfect custom interface) ... you could simply use:

typedef string Student;typedef int ClassID;typedef vector<ClassID> ClassList;typedef map<Student, ClassList> StudentScheduleMap;StudentScheduleMap studentSchedules;


I realize that quick example isn''t perfect or elegant, but it does show how truely powerful using templated classes can be ... cause in just a few lines of code, you have defined data structures which are type safe ... and even have overloaded operators ...

for example, in the example above (with certain restrictions), you can do things like the following:

Student aStudent("JohnSchwartz");int numClasses = studentSchedules[aStudent].size();// orClassID firstCourse = studentSchedules[aStudent][0];


I know these exmaples aren''t very great, but I''m just trying to illustrate the fact that the types of the object are fully known, so you can use all the operators and functions for the type you actually have ... not just what is available in some arbitrary base type.

Now polymorhism still gets used, but in neat ways like this:

list<ScreenObject*> onScreenObjects;for(onScreenObjects::iterator currentObject = onScreenObjects.begin(), currentObject != onScreenObjects.end(), ++currentObject;  {  currentObject->Draw();  }


which would tell every object to draw itself ... (assuming the ScreenObject class has a virtual Draw function).
Advertisement
Now polymorhism still gets used, but in neat ways like this:
list<ScreenObject*> onScreenObjects;for(onScreenObjects::iterator currentObject = onScreenObjects.begin(),     currentObject != onScreenObjects.end(),     ++currentObject;{  currentObject->Draw();} 


Or, even niftier
std::list<ScreenObject*> onScreenObjects;std::for_each(onScreenObjects.begin(),               onScreenObjects.end(),              std::mem_fun( &ScreenObject::Draw ) ); 


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

[edited by - Fruny on November 9, 2003 3:51:48 AM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
ah, cheers for that example Fruny, i''m working on something right now that that might well help with
yeah frunny, I was gonna do that, but I couldn''t remember the std::mem_fun syntax - I would highly recommend every C++ programmer purchase one of the STL (or just Standard Library) books published by addison wesley, I personal use the Nicolai Josuttis book (but it is in storage until next week, cause I''m moving ...)

for those getting started, I find that the following two containers are the most versitile until you know enough to choose others correctly - deque and map. The vector, deque, and list class pretty much do the exact same thing, but with different implementations, so they have WILDLY different performance costs for different operations -

use vector for few insertions or deletions, but fastest random access.

use list for fast insertions and sorting, but no random access.

use deque for a decent balance and when you don''t yet know the access behavior.

the set and map classes are different, because they don''t keep the items in any order you control, but instead hash the data into a list for quick access. The map is for when you need to lookup an element by some key type, and the set it for the same thing, except that the key is an operation on the item itself ... for example a map would give you a mapping to look up Student records by ID, but a set would keep a set of student records, compared to each other using the overloader == or != operators.

these container are highly useful even before you really understand iterators, but once you add iterators and generic container functions (such as foreach, merge, find) to them, you have enourmous power at your disposal.

after a few months of using the STL, I then recommend you look up "functors" and "binders" - both of which just add another amazingly usefull layer to the generic programming toolbox - but both of which are often harder for people to learn correctly then the container classes. binders have very confusing and difficult syntax for a beginner - functors are not hard, just often misunderstood or mistused.
quote:Original post by Xai
the set and map classes are different, because they don''t keep the items in any order you control, but instead hash the data into a list for quick access.


Set and map are not hashes. They guarantee O(log n) access, which implies they are tree-based. And the traversal order is well-defined: you get the elements in ascending order, based on the comparison operation *you* defined.

[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
I appologize for my incorrect information ... everyone head Fruny''s post

I guess I had just never made that connection and definately hadn''t read that the standard said their order was defined ... I always just assumed they we''re ordered for internal access speed and that the implementation would decide that so I never even tried to see if the order was anything usefull ... but I am fairly sure now that I was wrong, and you are right ...

I do know for sure that you are right about the implementation as exists in my compiler ... I just don''t have a copy of the standard to double check the rules about element ordering.
to be blunt and ultra simplistic, a template is like a macro, it replaces the occurences of T with whatever you supply. T is usually a type definition, but can be a number.

template<typename T>void Sort(T* Array, int Size){....}template<typename T, int SIZE>struct CArray{    T m_Elts[SIZE];    void Init(T* Elts);};template<typename T, int SIZE>void CArray<T, SIZE>::Init(T* Elts){...}CArray<int, 245> myArray;



Everything is better with Metal.

This topic is closed to new replies.

Advertisement