Presentation is loading. Please wait.

Presentation is loading. Please wait.

Andy Wang Data Structures, Algorithms, and Generic Programming

Similar presentations


Presentation on theme: "Andy Wang Data Structures, Algorithms, and Generic Programming"— Presentation transcript:

1 Andy Wang Data Structures, Algorithms, and Generic Programming
Templates Andy Wang Data Structures, Algorithms, and Generic Programming

2 Templates Provide generic programming Goal: Generic classes
Generic functions Generic algorithms (later lectures) Goal: Program reuse Templates The principal mechanism in C++ for defining generics is the template. The idea behind templates is quite simple: when defining a container, for example, a parameter is used to represent the element_type; when using the container, a specific class may be substituted for the template parameter. Templates are used in defining three distinct kinds of generics: generic classes, generic functions, and generic algorithms. Generic functions and classes are discussed later in this chapter. Generic algorithms, which depend on the concept of iterator, are discussed in subsequent chapters. Any legal C++ identifier may be used to name a template parameter. Just as with ordinary identifiers, it can be useful to use parameter names that are self-documenting. In our examples, we will often use T as a template parameter, where "T" can be thought to represent "template" or "type" (or the keyword "typename"). The template parameter is used in coding the function body or class implementation as though it were a known type. Any methods or operators for T that are used in this coding will eventually be called for a specific substituted type, and the compiler will report an error if these methods or operators are not defined for the substituted type.

3 Motivating Example Find the largest element in an array
int largest(const int *iptr, unsigned int size) { int current_largest = *iptr; for (; size > 0; --size, ++iptr) { if (current_largest < *iptr) { current_largest = *iptr; } return current_largest; Example Functions Shown in this slide are several functions called "largest". Each of these functions accomplishes essentially the same task, namely finding the largest value in an array of values. These functions differ only in the type that is passed through parameters and returned as a value. We could easily make up many more of these functions, one for almost any type or even user-defined class. The only requirement on the type is that the less-than operator <() be defined for the type. This situation is a perfect setup for templates.

4 Motivating Example Find the largest element in an array
float largest(const float *iptr, unsigned int size) { float current_largest = *iptr; for (; size > 0; --size, ++iptr) { if (current_largest < *iptr) { current_largest = *iptr; } return current_largest;

5 Motivating Example Find the largest element in an array
double largest(const double *iptr, unsigned int size) { double current_largest = *iptr; for (; size > 0; --size, ++iptr) { if (current_largest < *iptr) { current_largest = *iptr; } return current_largest;

6 Motivating Example int int_array[20]; float float_array[30];
double double_array[40]; cout << largest(int_array, 20) << “ “ << largest(float_array, 30) << “ “ << largest(double_array, 40);

7 Function Template Example
Find the largest element in an array template <typename T> T largest(const T *iptr, unsigned int size) { T current_largest = *iptr; for (; size > 0; --size, ++iptr) { if (current_largest < *iptr) { current_largest = *iptr; } return current_largest; Function Template Example In this slide we see how to use a template parameter to define a generic function called "largest" that replaces all three of the type-specific examples of the previous slide. Moreover, whenever we need a function "largest" for a new type, whether built-in or user-defined, we can use this same generic function. All we need do is call the function for the type, and make sure the generic code is available to the compiler. The compiler handles the rest: it substitutes our type into the template and creates code for that specific "largest" function. Example use of largest() for three different types is also shown in this slide.

8 In-Class Exercise Swap two values of the same type
Template Function Example 2 This slide shows code for another generic function that swaps the values of two variables of the same type. Note that the two parameters are passed to the function by reference, so that changes are made to the values in the calling routine.

9 Function Template Example 2
Swap two values of the same type template <typename T> void swap (T& t1, T& t2) { T temp; temp = t1; t1 = t2; t2 = temp; } Template Function Example 2 This slide shows code for another generic function that swaps the values of two variables of the same type. Note that the two parameters are passed to the function by reference, so that changes are made to the values in the calling routine.

10 Class Template Example
A class that holds a pair of items template <typename T> class Pair { public: T first; T second; Pair(); Pair(T t1, T t2); }; Template Class Example This slide shows the definition and implementation of a template class called "Pair". An object of type Pair<T> is an ordered pair of T objects. For example, an object of type Pair<int> is an ordered pair of ints; an object of type Pair<widget> is an ordered pair of widgets. Declaration of such objects works as follows: Pair<int> intPair;Pair<widget> widgetPair;// yada dada Spacing may be added in template declarations for readability or style, as follows: Pair < int > intPair;Pair < widget > widgetPair;// yada dada When nesting template declarations, some spacing is essential to avoid syntactic ambiguity, as in: Pair < widget < char > > charwidgetPair;Pair < Pair < char > > intQuad;// yada dada(where widget is a template class). If the two right angle brackets are not spaced, the compiler finds the right shift operator >> (or an overload of it) in a peculiar place!

11 Class Template Example
Constructors (in the same header file) template <typename T> Pair<T>::Pair() { } Pair<T>::Pair(T t1, T t2) : first(t1), second(t2) {

12 Class Template Example
Declarations Pair<int> intPair(1, 2); Pair<float> floatPair(1.1, 2.2); Pair< Pair<int> > pair(intPair, intPair); You need the space

13 Class Template Example 2
A class that holds a pair of items with different types template <typename T1, typename T2> class Pair { public: T1 first; T2 second; Pair(); Pair(T1 t1, T2 t2); }; Template Class Example 2 This slide illustrates the use of more than one template parameter in a class definition. The example is a Pair class with different types for the two items being paired.

14 Class Template Example 2
Constructors template <typename T1, typename T2> Pair<T1, T2>::Pair() { } Pair<T1, T2>::Pair(T1 t1, T2 t2) : first(t1), second(t2) {

15 Template Code Files Place template class definitions and implementation in the same header file Protect files from nested inclusions #ifndef _YADDY_H #define _YADDY_H #endif _YADDY_H Template Code Files Template code files follow a somewhat different set of conventions from regular code files. The fact behind the adoption of this convention is that template code cannot be translated into object code until it has first been converted into actual code by substituting a specific type for the template parameter (or types for parameters, if there are multiple template parameters). The reason is simple: object code needs to have size information about its variables in order to make a sensible memory model for the computation. Without knowledge of the type to be used for the template parameter, this is not possible. Thus template code needs to be pre-processed into real code at the source level before translation to object code can occur. The main reason for going to the trouble of separating regular code into header files and implementation files is so that the implementations can be pre-compiled to object code and stored in libraries. The header file gives the definitions of classes and prototypes of functions for client programs to use, but the implementation code is pre-translated. This saves time in compilation, and it also allows implementation source code to be kept proprietary. Because the possibility of pre-compiling the implementations of template functions and template class methods is not there, there is no reason to maintain separate files, and the custom is not to do so. We follow that custom in our course library. Here are two example file contents, one for a class template and one for a function template. First the funtcion template: /* swap.h Feb 3, Chris Lacher  Example of a template function header file*/ #ifndef _SWAP_H#define _SWAP_H template <typename T>void swap (T& t1, T& t2){ T temp; temp = t1; t1 = t2; t2 = temp;} #endif Note that there is no template function prototype, we simple write the function header and proceed directly to the implementation. The use of the #ifndef directive as illustrated in these two files serves to protect against multiple reads of the files. The effect is to define the symbol (a mutated file name) the first time the file is read and then to skip reading all subsequent times, because the symbol has been defined. The symbol serves no purpose in the actual trsanslation. /* Pair.h Feb 3, Chris Lacher  Example of a template class header file*/ #ifndef _PAIR_H#define _PAIR_H template <typename T>class Pair{ public: // no private components T first; T second; Pair(); // default constructor Pair (T t1, T t2); // constructor with parameters} ; template <typename T> // a template functionPair<T>::Pair() // scope resolution operator{}  template <typename T>Pair<T>::Pair(T t1, T t2) : first (t1), second (t2) // initialization list{} #endif Note that the method implementations are function templates and are placed in the header file following the template class definition. An alternative is to use a #include directive that pulls an implementation file into the header file, if there is some reason to have the implementation in a separate file. This makes the code "appear" to be in the same file because the #include directive is performed before translation takes place. Examples of either method of logically including class method implementations in the header file are used in the course library.

16 Next Two Class Meetings
9/15, 9/17 MCH 201


Download ppt "Andy Wang Data Structures, Algorithms, and Generic Programming"

Similar presentations


Ads by Google