1 / 12

From Last Time: Search with Generic Iterators

From Last Time: Search with Generic Iterators. Third generalization: separate iterator type parameter We arrive at the find algorithm (Austern pp. 13): template < typename Iterator, typename T> Iterator find ( Iterator first, Iterator last, const T & value) {

cmazza
Download Presentation

From Last Time: Search with Generic Iterators

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. From Last Time: Search with Generic Iterators • Third generalization: separate iterator type parameter • We arrive at the find algorithm (Austern pp. 13): template <typename Iterator,typename T> Iterator find (Iterator first,Iterator last, const T & value) { while (first != last && *first != value) ++first; return first; } • Which kinds of iterators will work with this algorithm? • How can we determine that from the algorithm itself?

  2. Key Ideas: Concepts and Models • A concept gives a set of type requirements • Classify/categorize types (e.g., random access iterators) • Tells whether or not a type can or cannot be used with a particular algorithm (get a compiler error if it cannot) • E.g., in the examples from last time, we could not use a linked list iterator in find1 or even find2, but we can use one in find • Any specific type that meets the requirements is a model of that concept • E.g., list<char>::iterator vs. char *in find • Different abstractions (bi-linked list iterator vs. char array iterator) • No inheritance-based relationship between them • But both model iterator concept necessary for find

  3. Concepts and Models, Continued • What very basic concept does the last statement of find, (the line return first;) assume? • Asked another way, what must be able to happen to first when it’s returned from function find? • Same requirement imposed by by-value iterator parameters • What other capabilities are required of the Iterator and T type parameters by the STL find algorithm ? template <typename Iterator, typename T> Iterator find (Iterator first, Iterator last, const T & value) { while (first != last && *first != value) ++first; return first; }

  4. Matching an Algorithm to the Iterators it Needs What STL iterator category does findrequire?

  5. Iterator Concept Hierarchy “transient” write to stream (ostream) “destructive” read at head of stream (istream) • read or write a value (one-shot) Input Iterator Output Iterator Singly-inked-list style access (forward_list) • value persists after read/write • values have locations • can express distancebetween two iterators Forward Iterator Bi-linked-list style access (list) Bidirectional Iterator is-a (refines) Array/buffer style access (vector, deque) Random Access Iterator

  6. What if an Algorithm Has Alternative Versions? // Based on Austern, pp. 38, 39 template <class Iter, class Distance> void move (Iter i, Distance d, fwd) { while (d>0) {--d; ++i;} // O(d) } template <class Iter, class Distance> void move (Iter i, Distance d, rand) { i += d; // O(1) } template <class Iter, class Distance> void move (Iter i, Distance d) { move (i, d, iterator_traits<Iter>:: iterator_category() ) } • Static dispatching • Implementations provide different signatures • Iterator type is evaluated at compile-time • Links to the best implementation • Notice how type tags are used concrete tag (empty struct) type concrete tag (empty struct) type default constructor (call syntax)

  7. Iterator Traits and Category Type Tags struct input {}; // empty structs for type tags struct output {}; struct fwd : public input {}; // note inheritance struct bidir : public fwd {}; struct rand : public bidir {}; template <typename I> struct iterator_traits { ... typedef typename I::iterator_category iterator_category; }; template <typename T> struct iterator_traits<T*> { ... typedef rand iterator_category; }; template <typename T> struct iterator_traits<const T*> { ... typedef rand iterator_category; }; • Need a few concrete types to use as tags • E.g., empty structs • E.g., input, output, fwd, bidir, and rand • Tags provide yet another associated type for iterators • Iterator category • Again, made available by using the traits idiom (actually, random_access_iterator_tag)

  8. Can Extend STL Algorithms with Callable Objects • Make the algorithms even more general • Can be used parameterize policy • E.g., the order produced by a sorting algorithm • E.g., the order maintained by an associative containe • Each callable object does a single, specific operation • E.g., returns true if first value is less than second value • Algorithms often have overloaded versions • E.g., sort that takes two iterators (uses operator<) • E.g., sort that takes two iterators and a binary predicate, uses the binary predicate to compare elements in range

  9. Callable Objects and Adapters • Callable objectssupportfunction call syntax • A function or function pointer bool (*PF) (const string &, const string &); // function pointer bool string_func (const string &, const string &); // function • A struct or class providing an overloaded operator() struct strings_ok { bool operator() (const string &s, const string &t) { return (s != “quit”) && (t != “quit”); } }; • A lambda expression (unnamed inline function) [quit_string] (const string &s, const string &t) -> bool {return (s != quit_string) && (t != quit_string);} • Adapters further extend callable objects • E.g., bind any argument using bind and _1 _2 _3 etc. • E.g., wrap a member function using mem_fn • E.g., wrap callable object with function (associates types)

  10. Using Functions with an Algorithm #include <iostream> #include <vector> #include <string> #include <iterator> #include <algorithm> using namespace std; struct Employee { Employee (const char * n, int i) : name_(n), id_(i) {} string name_; int id_; }; typedef Employee * EmployeePtr; ostream& operator<< (ostream & os, const EmployeePtr & e) { os << e->name_ << " " << e->id_ << " "; return os; } // function for comparing EmployeePtrs bool id_compare (const EmployeePtr & e, const EmployeePtr & f) { return e->id_< f->id_|| (e->id_ == f->id_ && e->name_ < f->name_); } int main (int, char *[]) { vector<EmployeePtr> v; v.push_back(new Employee("Claire", 23451)); v.push_back(new Employee("Bob", 12345)); v.push_back(new Employee("Alice", 54321)); cout << "v: " ; copy (v.begin(), v.end(), ostream_iterator<EmployeePtr>(cout)); cout << endl; // "v: Claire 23451 Bob 12345 Alice 54321 " sort (v.begin(), v.end(), id_compare); cout << "v: " ; copy (v.begin(), v.end(), ostream_iterator<EmployeePtr>(cout)); cout << endl; // "v: Bob 12345 Claire 23451 Alice 54321 " // clean up: pointers "own" the heap objects for (vector<EmployeePtr>::iterator i = v.begin(); i != v.end(); ++i) { delete *i; } return 0; } heap object pass function name

  11. count_if algorithm Generalizes the count algorithm Instead of comparing for equality to a value Applies a given predicate function object (functor) If functor’s result is true, increases count #include <iostream> #include <vector> #include <algorithm> using namespace std; template <typename T> // covers many types struct odd { bool operator() (T t) const { return (t % 2) != 0; } }; int main (int, char * []) { vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(2); cout << "there are " << count_if(v.begin(), v.end(), odd<int>()) << " odd numbers in v" << endl; return 0; } Using Function Objects with an Algorithm /* output is there are 2 odd numbers in v */

  12. Concluding Remarks • STL algorithms give you useful, generic functions • Combine easily with a variety of containers/iterators • Support many common data structure manipulations • Finding and modifying values, re-ordering, numeric operations • Reusing them saves you from writing/debugging code • Many STL algorithms can be extended • Especially by plugging callable objects (functors) into them • C++11 lambdas & the bind function give new ways to do that • Think about how iterators and algorithms combine • Think about which category of iterator a container provides • Think about the concept each iterator models • Think about the type requirements an algorithm imposes • Think about which combinations are valid, accordingly

More Related