Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chapter 8 Writing Generic Functions. Objectives Understand the use of generic functions. Learn about the use of templates, their advantages and pitfalls.

Similar presentations


Presentation on theme: "Chapter 8 Writing Generic Functions. Objectives Understand the use of generic functions. Learn about the use of templates, their advantages and pitfalls."— Presentation transcript:

1 Chapter 8 Writing Generic Functions

2 Objectives Understand the use of generic functions. Learn about the use of templates, their advantages and pitfalls. Examine the use of type parameters. Further investigate the theory and properties of iterators including the different types of iterators See how iterators can be used in input and output.

3 C++ Sometimes it pays to stay in bed on Monday, rather than spending the rest of the week debugging Monday's code. - Christopher Thompson Measuring programming progress by lines of code is like measuring aircraft building progress by weight. - Bill Gates 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.

4 Generic Functions The functions we have created so far have specific parameter and return types. We have used library functions that could work on many different types. – The find function can find entries of any type in several different types of containers. The problem is this, how do we determine which types make sense for a particular function and which do not? – e.g. we can average ints, floats, doubles, complex numbers, etc. but what do we mean by an average string ?

5 Generic Functions The find function accepts two iterators and a value as parameters. We can used the function with different types of iterators, but they must be iterators. The important point here is that find uses operations that only iterators support so it doesn’t make sense to call it with other types of parameters.

6 Templates C++ uses a feature called templates to implement generic functions. We can write a single definition to create a family of functions (or types) that function similarly except for different template parameters. Objects of different types may share common behaviors. Template parameters let us write programs in terms of that common behavior.

7 Template Parameters We use a template parameter when we create a container type. vector The vector type and its associated functions work on different types of entries. We specify the type of the vector inside the angle brackets <>.

8 Medians Let’s create a median function that can calculate the median of vectors with other types besides double. The first step is to create a template header. template This indicates we are defining a template function and the function will use T as a type parameter. This is a variable that is used to specify a type. We will use the type parameter T to specify the types of other parameters and the return type.

9 Medians template T median(vector v) { typedef typename vector ::size_type vec_sz; vec_sz size = v.size(); if (size == 0) throw domain_error("median of an empty vector"); sort(v.begin(), v.end()); vec_sz mid = size/2; return size % 2 == 0 ? (v[mid] + v[mid-1]) / 2 : v[mid]; }

10 Medians We can use this function with any type of vector as long as the operations used are supported. – Sort – Addition – Division by 2 Suppose we create a vector of ints. vector x When we pass this vector to the median function it will use the type of the vector to determine the value for T. m = median(x) Since x is a vector we know that T is int.

11 Using Type Parameters We use the type parameter to specify the parameters types and the return type. T median(vector v) When we compile the code a specific version is created (instantiated) and will behave as if we had typed int in place of every T. This means we may end up with several different compiled versions of our function: one for ints, one for floats, etc.

12 typename We can create variables based on this type. typedef typename vector ::size_type vec_sz The reason we have the typename keyword here is that when we compile this code the computer may complain because vector is not yet a type and so doesn’t have a size_type attribute (yet). The problem is the vector class is not an integrated part of the compiler. The typename basically tell the the compiler “trust us, this will be a type eventually.”

13 Header Files Notice the compiler cannot completely compile a template function until it know the type. This implies we cannot do separate compilation. Instead of putting the declaration in the header file (.h ) and the code in a separate (.cc,.C,.cp,.cpp ) file we will put everything in the.h file. There will be a penalty in terms of compile time.

14 Problems with Types Be careful of the how types interact when using templates. find(s.homework.begin(), s.homework.end(), 0); This works with int, float and double because 0 automatically converts to 0.0. find(s.homework.begin(), s.homework.end(), 0.0); This won’t work with int because 0.0 does not convert to 0.

15 Problems with Types Still more problems. accumulate(v.begin(), v.end(), 0) This function creates an accumulator based on the type of the third argument. In this case it will work with float and double but the result will be truncated to an int. accumulate(v.begin(), v.end(), 0.0) This function works with int as well as float and double. The only potential problem is the return value will be a double.

16 Problems with Types Consider the following implementation of max. Template T max(const T& left, const T& right) { return left < right ? left : right; } Suppose we pass an int and a double. What is T ? Is it int or a double ? This is why the library max function insists its parameters must be exactly the same type.

17 Data Structure Independence Why do we need to specify all those iterators? find(c.begin(), c.end(), val) Why not just pass the structure and value? find(c, val) Or even use a method? c.find(val) There are three reasons. – Iterators allow us to find the value in part of a list. – The find function can work with any container. – Iterators can have special properties themselves rbegin marches backward through the structure.

18 Iterators and Algorithms Notice that some container classes support iterator operations that other do not. –it + 5 makes sense if it is an iterator to a vector but not if it is an iterator to a list. This means that some algorithms work with certain types of iterators but not others. –sort works for iterators to vectors but not for iterators to lists. There are five iterator categories that specify what operations and algorithms will work with them.

19 Sequential Read-Only Access These iterators are used to read the elements of a sequence and are called input iterators. Here input means getting data from the structure into the rest of our program. They must support the following operations. – Increment (pre and post) ( ++) – Equality comparison (==, !=) – Dereference (*, ->) All our iterators support these operations so they are all input iterators.

20 Sequential Write-Only Access We may need to use an iterator to write elements of a sequence, these are called output iterators. Notice the meaning of output and input are confusing when it comes to iterators! They must support the following operations. – Assignment ( *it = value ) – Increment (pre and post) (++) – The restriction that we cannot increment twice in a row without an assignment (skip an entry in our output to the structure). – The restriction that we cannot assign twice without an increment (overwrite an existing entry). All our iterators can be used this way. back_inserter enforces the restrictions.

21 Sequential Read-Write Access Some iterators can only be incremented but not decremented (we can only travel in one direction through the structure). These are called forward iterators. They support the following operations. – Dereferencing (*, ->) for both reading and writing. – Increment (pre and post) (++) – Equality comparison (==, !=) These iterators do not necessarily support decrement (--).

22 Reversible Access If we can move both backward and forward through the structure then it is a bidirectional iterator. It must support the forward operations in addition to the decrement operator (pre and post) (--). The standard-library container classes all support-bidirectional iterators.

23 Random Access Some functions need to jump around in a container. Many sorting and searching algorithms need iterators that can jump. Iterators that support this are random-access. We need to be able to do arithmetic on our iterators so there are additional required operations. – Arithmetic between an integer n and an iterator p ( p + n, p - n, n + p ) – Arithmetic between iterators p and q ( p – q ) – Indexing ( p[n] which is equivalent to *(p + n) ) – Comparison ( p q, p = q ) Only vector and string iterators are random-access.

24 Off-the-end Iterators Why does end() produce an iterator that is one past the last entry in the structure? There are several reasons. – It is easier to write loops that run through the entire structure and do not need to treat the last element as special. –end() makes sense even for empty lists. – For all but random-access iterators we only need to compare iterators for equality (==, !=). You don’t need to check for <= end. – It gives us a natural return value when a function fails. What should find(c.begin(), c.end(), 0) return if there are no 0’s in the structure?

25 Input and Output Iterators All our standard-library containers support are input, output and forward iterators. Not all iterators fall into all three categories. –back_inserter is an output only iterator. Iterators can be associate with things other than containers. – Iterators for istream are input iterators. – Iterators for ostream are output iterators.

26 Input Stream Iterator With an input stream iterator we can read from input and store the results in a container using the standard copy function. copy(istream_iterator (cin), istream_iterator (), back_inserter(v)) This actually creates a beginning iterator bound to the the input stream cin. Notice we need to specify the type to read when we create the iterators. The ending iterator is a default iterator. This will be the value that will result when we reach end-of-file or some other error state.

27 Output Stream Iterators We can also use iterators to copy a container to output. copy(v.begin(), v.end(), ostream_iterator (cout, “ “)); Notice that the ostream_iterator will be used to send int values to cout and they will be separated by spaces. The following would print without any spaces. copy(v.begin(), v.end(), ostream_iterator (cout));

28 Split Revisited We can make an improvement to our split function. Instead of returning a vector of strings, we will return any type of container that can hold strings. The function will now accept an output iterator instead of returning a value. We will write the words we find to the structure associated with this iterator (whatever that is).

29 Split Revisited template // changed void split(const string& str, Out os) { // changed typedef string::const_iterator iter; iter i = str.begin(); while (i != str.end()) { i = find_if(i, str.end(), not_space); iter j = find_if(i, str.end(), space); if (i != str.end()) *os++ = string(i, j); // changed i = j; } }

30 Split Revisited The type of the iterator os is used to define the type parameter Out. We only use the iterator os in one place. *os++ = string(i, j); So we only need the operations of increment (++) and dereferencing for assignment ( *it = ). We can use an output iterator with this function.

31 Using Split We could use split to put the resulting words in any appropriate container. split(s, back_inserter(word_list)); We could also use split to send the results to output. int main() { string s; while (getline(cin, s)) split(s, ostream_iterator (cout, "\n")); return 0; }

32 Templates for Functions without Arguments If we have a function that does not have an argument list we can still use templates. template T zero() { return 0; } To call this function we need to supply the turn type. double x = zero ();

33 Homework Chapter 8 (page 154) Total 45 pts possible. – 8-0 – 8-2 (equal, find, find_if, copy, transform) (email, 10 pts each) – 8-4 (paper, 10 pts) – 8-7 (paper, 5 pts) – 8-8 (paper, 5 pts)


Download ppt "Chapter 8 Writing Generic Functions. Objectives Understand the use of generic functions. Learn about the use of templates, their advantages and pitfalls."

Similar presentations


Ads by Google