1 / 73

Template Mechanism: Reusing Code in C++

Learn how templates in C++ allow for the parameterization of functions and classes, enabling code reuse and genericity.

dnovotny
Télécharger la présentation

Template Mechanism: Reusing Code in C++

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Templates and Standard Containers Chapter 6

  2. Templates • Templates allow functions and classes to be parameterized • type of data being operated upon (or stored) is received via a parameter. • Templates provide a means to reuse code • One template definition can be used … • to create multiple instances of a function (or class), • each operating on (storing) a different type of data. • The template mechanism is important and powerful. • It is used throughout the Standard Template Library (STL) to achieve genericity.

  3. Templates

  4. Functions • Rationale for functions: • Make pieces of code reusable • Encapsulating them within a function. • Consider the task of swapping the values stored in two variables void Swap (int & first, int & second){int temp = first; first = second; second = temp; }

  5. Integer Solution • Function Swap gives a general solution to the interchange problem for ints • This Swap function can be used to exchange the values of any two integer variables • In contrast, inline code would have to be rewritten for each pair of integer variables to swap.

  6. Swap for Doubles • To interchange the values of two double variables: • Can't use the preceding function; it swaps ints • Overloading allows us to define multiple versions of the same function: void Swap (double & first, double & second) • Different Swap functions are distinguished by the compiler according to a function's signature • name, number, type and order of parameters

  7. Swap for Strings • To interchange the values of two string variables: • Again, overload function Swap(): void Swap(string & first, string & second){string temp = first; first = second; second = temp; }

  8. Swap Library • Why not create a library of all possible types to swap • Would work for predefined C++ types • but not for user defined types • must overload for each user defined type void Swap(Time & first, Time & second){Time temp = first; first = second; second = temp; }

  9. Observations • The logic for each version of the Swap function is exactly the same • The only difference is in the type of the values being exchanged • Consider passing the type as a parameter! • Write a general solution • Could be used to exchange two values of any type

  10. Template Mechanism • Declare a type parameter • also called a type placeholder • Use it in the function instead of a specific type. • This requires a different kind of parameter list: void Swap(______ & first, ______ & second) {________ temp = first; first = second; second = temp;}

  11. Template Mechanism • The word template is a C++ keyword • Specifies that what follows is … • a pattern for a function • not a function definition. • “Normal” parameters (and arguments) • appear within function parentheses • Type parameters (and arguments for class templates) • appear within template angle brackets (< > ).

  12. Template Mechanism • A function template cannot be split across files • specification and implementation must be in the same file • A function template is a pattern • describes how specific functions is constructed • constructed based on given actual types • type parameter said to be "bound" to the actual type passed to it

  13. Template Mechanism • Each of the type parameters must appear at least once in parameter list of the function • compiler uses only types of the arguments in the call • thus determines what types to bind to the type parameters

  14. Function Template template <typename ElementType> void Swap (ElementType &first, ElementType &second) { ElementType hold = first; first = second; second = hold; }

  15. Function Template template <typename ElementType> void Swap (ElementType &first, ElementType &second) • Originally, the keyword class was used instead of typename in a type-parameter list. • "class" as a synonym for "kind" or "category"— specifies "type/kind" of types.

  16. Function Template • <typename ElementType> names ElementType as a type parameter • The type will be determined … • by the compiler • from the type of the arguments passed • when Swap() is called.

  17. General Form of Template template <typename TypeParam>FunctionDefinition or template <class TypeParam>FunctionDefinition where: TypeParam is a type-parameter (placeholder) naming the "generic" type of value(s) on which the function operates FunctionDefinition is the definition of the function, using type TypeParam.

  18. Template Instantiation • A function template is only a pattern • describes how individual functions can be built from given actual types. • This process of constructing a function is called instantiation. • In each instantiation, the type parameter is said to be bound to the actual type passed. • A template thus serves as a pattern • for the definition of an unlimited number of instances.

  19. Template Instantiation • In and of itself, the template does nothing. • When the compiler encounters a template • it stores the template • but doesn't generate any machine instructions. • Later, when it encounters a call to Swap() • Example: Swap(int1, int2); • it generates an integer instance of Swap()

  20. Template Instantiation • Algorithm for instantiation • Search parameter list of function template for type parameters. • If one is found, determine type of corresponding argument. • Bind these types. • The compiler must actually "see" the definition of the function • not just the prototype • thus the requirement – a function template cannot be split across two files

  21. Programming Style Tip • For efficiency (and often correctness), compilers frequently recommend: Explicit instantiation: Provide a prototype of function to be later instantiated to the compiler. • void Swap(int, int); void Swap(double, double); void Swap(string, string); void Swap(Time, Time);

  22. Exercise • Write a function template which will find the largest element in an array • Write a driver program which will test this with at least three different instantiations • Apply concepts and tips presented in the lecture

  23. Templates With Multiple Parameters Given: template <typename Type1, typename Type2 >void whatEver (Type1, Type2){ … } • Each type parameter must appear • at least once • in the function's parameter list. • Compiler must be able to determine actual type corresponding to each type parameter from a function call. Why?

  24. Templates With Multiple Parameters • Example template <typename Type1, typename Type2>void Convert(Type1 value1, Type2 & value2){ value2 = static_cast<Type2>(value1);} • What does this function do? • Write a driver program to try it out

  25. Templates With Multiple Parameters • The following version of function template Convert would not be legal … Why?? template <typename Type1, typename Type2>Type2 Convert(Type1 value1) { return static_cast<Type2>(value1);} Type2 is not in the parameter list

  26. Solution • We could provide a dummy second parameter indicating the type of the return value: template <typename Type1, typename Type2>Type2 Convert(Type1 value1, Type2 value2){ return static_cast<Type2>(value1);} • Function call: double x = 3.14; int ix = Convert(x, 0);

  27. Another Solution #include <iostream>using std::cout;using std::endl;template<typename type1, typename type2>type1 convert(type2 value){ return static_cast<type1>(value);}int main(){ float pi=3.14159F; cout << convert<int>(pi) << endl;}

  28. Class Templates Recall our Stack class: const int STACK_CAPACITY = 128; typedef int StackElement; class Stack { /***** Function Members *****/ public: . . . /***** Data Members *****/ private: StackElement myArray[STACK_CAPACITY]; int myTop; }; How did we create a new version of a stack for a different type of element?

  29. What’s wrong with typedef? • To change the meaning of StackElement • Merely change the type following typedef • Problems: • Changes the header file • Any program that uses this must be recompiled • A name declared using typedef can have only one meaning. • What if we need two stacks of different types in the same program? • cannot overload like functions (same number, type, and order of parameters)

  30. StackElement is a “blank” type (a type placeholder)to be filled in later. template <typename StackElement> Type-Independent Container • Use a class template: • the class is parameterized • it receives the type of data stored in the class • via a parameter (like function templates). • Recall const int STACK_CAPACITY = 128; __________________________________ class Stack{/***** Function Members *****/public: . . ./***** Data Members *****/private:StackElement myArray[STACK_CAPACITY]; int myTop;};

  31. General Form Of Class Template Declaration template <typenameTypeParam> or template <classTypeParam> class SomeClass{ // ... members of SomeClass ... }; More than one type parameter may be specified:template <typename TypeParam1,..., typename TypeParamn>class SomeClass{ // ... members of SomeClass ...};

  32. Instantiating Class Templates • Instantiate it by using declaration of form ClassName<Type> object; • Passes Type as an argument to the class template definition. • Examples: Stack<int> intSt; Stack<string> stringSt; • Compiler will generate two distinct definitionsofStack • two instances • one for ints and one for strings.

  33. Rules For Class Templates • Definitions of member functions outside class declarationmust be function templates. • All uses of class name as a type must be parameterized. • Member functions must be defined in the same file as the class declaration.

  34. Applying the Rules to Our Stack Class • Recall how we specified the prototypes in the class • Used StackElement • Thus no changes needed – all rules OK • Apply Rule 1 • Each member functions definition preceded bytemplate <typename StackElement>

  35. Applying the Rules to Our Stack Class • Apply Rule 2 • The class name Stack preceding the scope operator (::) is used asthe name of a type • must therefore be parameterized. template <typename StackElement>void Stack<StackElement>::push(const StackElement & value) { /* ... body of push() ... */ } • Apply Rule 3 : specification, implementation in same file

  36. Applying the Rules to Friend Functions • Consider the addition of a friend functionoperator<< • Second parameter is of type Stack, must parameterized friend ostream & operator<<(ostream & out,const Stack<StackElement>& st);

  37. Applying the Rules to Friend Functions • When defining the operator<< function • It must be defined as a function template template<typename StackElement> ostream & operator<<(ostream & out, const Stack<StackElement> & st) { . . . }

  38. Exercise • Work together to complete a template version of the class Queue • Write a driver program to test it • Use at least three different types

  39. STL (Standard Template Library) • A library of class and function templates Components: • Containers: • Generic "off-the-shelf" class templates for storing collections of data • Algorithms: • Generic "off-the-shelf" function templates for operating on containers • Iterators: • Generalized "smart" pointers that allow algorithms to operate on almost any container

  40. begin() end() vector sort() Standard Template Library • Example of a specific • container class • iterator • algorithm

  41. STL's 10 Containers Kind of ContainerSTL Containers Sequential:deque, list, vector Associative:map, multimap, multiset, set Adapters:priority_queue, queue, stack Non-STL:bitset, valarray, string

  42. The vector Container • A type-independent pattern for an array class • capacity can expand • self contained • Declaration template <typename T> class vector { . . . } ;

  43. The vector Container • Constructors vector<T> v, // empty vector v1(100), // 100 elements of type T v2(100, val), // 100 copies of val v3(fptr,lptr); // contains copies of // elements in memory // locations fptr to lptr

  44. The vector Container • Vector operationsSee table on pg 270 • Vector object treated much like an array • without limitations of C-style arrays • Note how vector objects are self contained • able to manipulate their own "stuff"

  45. Iterators • Note from table that a subscript operator is provided • BUT … this is not a generic way to access container elements • STL provides objects called iterators • can point at an element • can access the value within that element • can move from one element to another • They are independent of any particular container … thus a generic mechanism

  46. v.begin() v.end() Iterators • Given a vector which has had values placed in the first 4 locations: • v.begin() will return the iterator value for the first slot, • v.end() for the next empty slot vector<int> v

  47. Iterators • Each STL container declares an iterator type • can be used to define iterator objects • To declare an iterator object • the identifier iterator must be preceded by • name of container • scope operator :: • Example:vector<int>:: vecIter = v.begin()

  48. Iterators • Basic operators that can be applied to iterators: • increment operator ++ • decrement operator -- • dereferencing operator * • Assignment = • Addition, subtraction +, -, +=, -=vecIter + n returns iterator positioned n elements away • Subscript operator [ ]vecIter[n] returns reference to nthelement from current position

  49. for (vector<double>::iterator it = v.begin(); it != v.end(); it++) out << *it << " "; Iterators Contrast use of subscript vs. use of iterator ostream & operator<<(ostream & out, const vector<double> & v){ for (int i = 0; i < v.size(); i++) out << v[i] << " "; return out;}

  50. Iterator Functions • Note table on pages 286, 287 • Note the capability of the last two groupings • Possible to insert, erase elements of a vector anywhere in the vector • Must use iterators to do this • Note also these operations are inefficient for arrays due to the shifting required

More Related