Generic Programming Templates: The Solution to Homogeneous Data Handling
Learn how to parameterize functions with templates and implement generic code using class and function templates. Understand the syntax, create template parameters, and handle data structures efficiently with C++ templates.
Generic Programming Templates: The Solution to Homogeneous Data Handling
E N D
Presentation Transcript
Version 1.0 Programming Techniques Course
Version 1.0 Chapter 11 –Templates And STL
Motivation • A function for finding minimum value int min(int a, int b) { return (a>b ? a : b) } • This is good for integers • For floats we will need another function float min(float a, float b) { return (a>b ? a : b) } • Can we parameterize this function with a type? • Towards Generic Programming • Like objects are generalized into classes, we would like to generalize classes and functions into templates.
Motivation • Even creating a macro out of it will not work in certain cases #definemin(a, b) ((a)>(b) ? (a) : (b)) • It will work for min(5, 10); min(5.0, 10.0) • Think of an example when it will not work …
Function Template • Preserving the semantics of a function • Automatically generated instance of a function, varying by type • The programmer parameterizes all or a subset of the types in the interface • The function implementation remains invariant over a set of function instances, each handling a unique data type template <class Type> Type min(Type a, Type b) { return ( a>b ? a : b); } Template parameter List
Template Syntax • template <class Type> • This line states that everything in the following declaration or definition is under the subject of the template. • In the brackets goes a list of “placeholders variables.” • In almost all cases, they will be specified with either the typename or class keywords. • Placeholder variables have one value within each template declaration. • Think of them as being replaced by whatever type you specify the template to be.
Class Templates • Creating a class, where a type or value is parameterized • Motivation • A bag (of what?) • How would we implement generic code for this problem? • An array of pointers to base class • Each type would have to inherit from the basic type • May be a problematic solution • Homogeneous vector can be achieved by a template solution • The template class defines a bag of elements once, in a general way • Programs using bags can instantiate separate bag classes for specific types of elements as necessary
Problem Solution: Templates • Template class for a data structure uses a .h file and, instead of a .cpp file, a .template file • When an object of a data structure type is instantiated, the type of data object it stores is specified • If the class for that object does not already exist, the class is instantiated at compile time • Then the object from that class is instantiated
Bags With and Without Templates • Differences between .template, .cpp files: • Occurrences of BagOfItems :: are replaced by Bag<Item> :: • Member functions, constructors, destructor are preceded by template<class Item> • Constructors are Bag; destructor is ~Bag • Assumption:Item is a class • See use of NULL in add, getOne
Instantiating Bag Objects Bag<int> bag(40); // statically allocated bag for 40 ptrs to int Bag<int> *bagPtr = new Bag<int>(60); // bagPtr holds the // address of a dynamically allocated bag that stores up // to 60 pointers to int Bag< Bag<int> > x(25); // statically allocated bag x can hold 25 // pointers to bags, each of which can hold pointers to int Bag< Bag<int > > *y = new Bag< Bag<int > > (30); // y holds // the address of a dynamically allocated bag that stores // up to 30 pointers to bags of pointers to int
Instantiating Bag Objects • When Bag<Bag<int>> b = new Bag<Bag<int>>(30); is first encountered: • First, the class Bag<int> is instantiated • Then the class Bag<Bag<int>> is instantiated • Then the object b is instantiated • When Bag<int> and Bag<Bag<int>> are encountered subsequently, the classes already exist
Using Bag Objects • Suppose a bag has been declared using Bag<int> b(20); • Member functions can be invoked on b in the normal fashion • Only pointers to int can be stored in b • Values returned by b.getOne( ) are always of type int* • Outside the class definition, Bag as a type name is changed to Bag<Item> • Rule holds even in the portion of the .h file where prototypes of non-member functions are declared; each of these prototypes is preceded by the prefix template <class Item> • In Bag.template, constructor and destructor names are still Bag, ~Bag
OrderedList.h #include “List.h” template <class Item> class OrderedList { public: OrderedList(unsigned int capacity = MAX_LIST); // constructor for // an empty ordered list that can hold up to capacity items; default // size is defined in List.h ~OrderedList( ); // destructor bool isEmpty( ) const; // true if list is empty, false otherwise
OrderedList.h int getLength( ) const; // returns the current size of the list // remove the value at location pos, and return it; precondition: // pos must be a legal list position Item remove (unsigned int pos); // return value at pos without modifying the list; precondition: // pos must be a legal list position Item retrieve (unsigned int pos) const; // cont’d..
OrderedList.h // insert item at appropriate pos’n in list void insert (Item item); // return pos’n of first occurrence of item, or -1 if item isn’t found int find (Item item) const; private: List<Item> m_container; // to hold the list of Items }; // end of header file
OrderedList.template #include <stdlib.h> template <class Item> OrderedList<Item> :: OrderedList (unsigned int capacity ) : m_container(capacity) { } template <class Item> OrderedList<Item> :: ~OrderedList ( ) { } // cont’d..
OrderedList.template template <class Item> bool OrderedList<Item> :: isEmpty( ) const { return m_container.isEmpty( ); } template <class Item> int OrderedList<Item> :: getLength( ) const { return m_container.getLength( ); } // cont’d..
OrderedList.template template <class Item> Item OrderedList<Item> :: remove (unsigned int pos) { return m_container.remove(pos); } template <class Item> Item OrderedList<Item> :: retrieve (unsigned int pos) const { return m_container.retrieve(pos); } // cont’d..
OrderedList.template template <class Item> void OrderedList<Item> :: insert (Item item) { unsigned int k; for ( k = 1; k <= getLength( ); k++ ) if ( item < retrieve(k) ) break; m_container.insert( k, item ); } // cont’d..
OrderedList.template template <class Item> int OrderedList<Item> :: find (Item item) const { unsigned int k; for ( k=1; k <= getLength( ); k++ ) if ( item == retrieve(k) ) return k; return –1; } // end of OrderedList implementation
STL – Why? • Reuse. • Reusable core components. • The programmer can focus on application development, and rely on for portability of components such as: strings, containers, algorithms (sort, search, etc.) and I/O streams. • STL had been designed with efficiency in mind • Better maintainability
STL Overview • For best Generality and Reusability, most of STL’s components are supplied as templates (functions and classes). • Three main component groups: • Containers - contain and organize other objects. • Iterators - provide a means of sequencing through the elements of a container in some order. • Algorithms - perform certain operations on containers’ elements. • Those components are independent of each other, pluggable, and exchangeable, through generic interface
Containers – Overview • An STLcontainer is an object that manages a collection of elements. • Different containers, with efficiency considerations • For search, operator== is required • For ordering, relational operators are needed, i.e. operator< is required • With common, generic interface • Also, default constructor, copy constructor, copy assignment operator and destructor are needed. • Sequence containers • Ordered collection (vector, deque, list) • Associative containers • Sorted collection (map, multimap, set and multiset) – fast retrieval
Containers Common Functionality • Common member functions for all STL containers: • empty– returns true if there are no elements in the container, otherwise returns false. • size– returns the number of elements currently in the container. • max_size– returns the maximum number of elements for a container. • erase– erase one or more elements from the container. • clear– erase all elements from the container. • swap– swaps the elements of two containers.
Iterators • The containers provide iteratorclasses, enabling element iteration and access functionality in a common and general interface
Algorithms Overview – cont’d • Algorithms are designed to be a “plug-in” to work on any container • Search algorithms • find, find_if, count, count_if, search, binary_search, etc. • Sorting algorithms • sort, merge, partition, etc. • Other modifying sequence algorithms • Relational & minimum / maximum algorithms • More…
Container of T Generic Algorithm Iterator generates uses Interconnectivity of Components • The connections between iterators, containers and algorithms: • Containers provide iterators as part of their interface. • Algorithms are defined in terms of iterators. • There is no direct connection between algorithms and containers. • The use of iterators enables writing generic algorithms which are applicable to any container class that provides a standard iterator.