320 likes | 615 Vues
Templates Example… A useful routine to have is void Swap( int& a, int &b ) { int tmp = a; a = b; b = tmp; } Example… What happens if we want to swap a double ? or a string ? For each one, we need different function: void Swap( double& a, double &b ) {
E N D
Example… A useful routine to have is void Swap( int& a, int &b ) { int tmp = a; a = b; b = tmp; }
Example… • What happens if we want to swap a double ? or a string? For each one, we need different function: void Swap( double& a, double &b ) { double tmp = a; a = b; b = tmp; } void Swap( string& a, string &b ) { string tmp = a; a = b; b = tmp; }
Generic Programming All these versions of Swap are “isomorphic” // template code for Swap for arbitrary type T void Swap( T& a, T &b ) { T tmp = a; a = b; b = tmp; } • Can we somehow tell the compiler to use Swap with any type T?
Templates The template keyword defines “templates” • Piece of code that will be regenerated with different arguments each time template<class T> // T is a “type argument” void Swap( T& a, T &b ) { T tmp = a; a = b; b = tmp; }
Template Instantiation int main() { int a = 2; int b = 3; Swap( a, b ); // requires Swap( int&, int& ) } • The compiler encounters Swap( int&, int& ) • It instantiates the template Swap with T = intand compiles the code defined by it
Template Instantiation • Different instantiations of a template can be generated by the same program • See Swap.cpp
Templates & Compilation • A template is a declaration • The compiler performs syntax checks only • When a template is instantiated with specific arguments, then the generated code is compiled Implications: • Template code has to be visible by the code that uses it (i.e., appear in .h file) • Compilation errors can occur only in a specific instance (see Swap.cpp)
Another Example… // Inefficient generic sort… template< class T > void Sort( T* begin, T* end ) { for( ; begin != end; begin++ ) for( T* q = begin+1; q != end; q++ ) if( *q < *begin ) Swap( *q, *begin ); } See [Sort.h, TestSort.cpp]
More Complex Case… • Suppose we want to avoid writing operator != for new classes template <class T> bool operator!= (T const& lhs, T const& rhs) { return !(lhs == rhs); } When is this template used?
More Complex Case… class MyClass { public: … bool operator==(MyClass const & rhs) const; … }; … int a, b; … if( a != b ) // uses built in operator!=(int,int) … MyClass x,y; if( x != y ) // uses template with T = MyClass …
When Templates are Used? When the compiler encounters … f( a, b ) … • Search for a function f() with matching type signature • If not found, search for a template function that can be instantiated with matching types
Generic Classes? • Suppose we implement a class StrList that maintains a list of strings • See StrList.h and StrList.cpp • The actual code for maintaining the list has nothing to do with the particulars of the string type • Can we have a generic implementation of lists?
Class Templates template<class T> class MyList { … }; … MyList<int> intList; // T = int MyList<string> stringList; // T = string
Class Templates Code similar to usual code: • Add template<…> statement before each top-level construct • Use template argument as type in class definition • Implementation of methods, somewhat more complex syntax • See MyList.h TestMyList.h
Constructing a List • We want to initialize a list from an array • We can write a method that receives a pointer to the array, and a size argument int array[] = { 1, 2, 3, 4, 5, 6 }; MyList<int> list; list.copy( array, 6 ); • Alternative: use a pointer to initial position and one to the position after the last list.copy( array, array+6 ); • This form is more flexible (as we shall see)
Constructing a List // Fancy copy from array template< class T > MyList<T>::copy( T const* begin, T const* end ) { T const* p; for( p = begin; p != end; p++ ) pushBack(*p); }
Pointer Paradigm Code like: T * p; for( p = begin; p != end; p++ ) { // Do something with *p … } • Applies to all elements in [begin,end-1] • Common in C/C++ programs • Can we extend it to other containers?
Iterator • Object that behaves just like a pointer • Allows to iterate over elements of a container Example: MyList<int> L; … MyList<int>::iterator i; for( i = L.begin(); i != L.end(); i++ ) cout << " " << *i << "\n";
Iterators To emulate pointers, we need: • copy constructor • operator = (copy) • operator == (compare) • operator * (access value) • operator++ (increment)
MyList<T> iterator • Keep a pointer to a node class iterator { … private: Node m_pointer; }; • Provide encapsulation, since through such an iterator we cannot change the structure of the list See MyListWithIterators.h
Side Note operator++ In C we can use ++ in two forms: • prefix notation ++x • increment x • fetch x’s value • postfix notation x++ • fetch x’s value • increment x How can we implement both variants?
Operator++ • Prefix form: T& T::operator++(); • Postfix form T T::operator++(int); // dummy argument! • Note different return types See MyListWithIterators.h
Initializing a List • We now want to initialize a list from using parts of another list • Something like template< class T > MyList<T>::copy( iterator begin, iterator end ) { iterator p; for( p = begin; p != end; p++ ) pushBack(*p); }
Generic Constructor • The code for copying using • T* • MyList<T>::iterator are essentially identical • on purpose --- iterators mimic pointers Can we write the code once?
Template within a template template < class T > class MyList { … template< class Iterator > copy( Iterator begin, Iterator end ) { for( Iterator p = begin; p != end; p++ ) pushBack(*p); } … };
Copy Method • MyList<T>::copy() can be instantiated with different types • pointer to T • MyList<T>::iterator • Iterators of other data structures that contain objects of type T
Template Variations • Can receive constant arguments template< class T, int Size = 1024> class Buffer { … private: T m_values[Size]; }; … Buffer<char> Buff1; Buffer<char,1024> Buff2; // same as Buff1 Buffer<int, 256> Buff3;
Template and Types • Buffer is not a type • Buffer<char,1024> is a type • Buffer<char>, buffer<char,1024> are two names for the same type • Buffer<char,256> is a different type
Class Templates - Recap • Provides support for generic programming • Parameters are either types or constants. Default values can be specified • Depends only on the properties it uses from its parameter types • Resulting classes may be very efficient, but code size may be larger • Difficult to write, maintain and debug • Class template overloading is impossible
Summary • Alternative mechanism to polymorphism • Write & Debug concrete example (e.g., StringList) before generalizing to a template • Understand iterators and other “helper” classes • Foundation for C++ standard library (STL)
Things to read about Standard Library • <string> – implementation of string • <algorithm> - algorithms (sort, swap, etc.) • <utility> - relational operators