Better Software - January 2008 - (Page 12) Code Craft // Listing 5: Generalizes the callable type template class Composer { private: // Deduce function and return/argument types typedef typename iterator_traits ::value_type Fun; typedef typename Fun::result_type T; // Declare reverse iterators (see constructor for use) typedef reverse_iterator RevIter; RevIter beg, end; // The function called by accumulate static T apply(T sofar, Fun f) { return f(sofar); } public: Composer(Iter b, Iter e) : beg(RevIter(e)), end(RevIter(b)) {} T operator()(T x) { return accumulate(beg, end, x, apply); // Function Applicator } }; Listing 5 ment by three. The divides function object comes with the standard C++ library, as does the bind2nd function-object adaptor, which converts divides into a single-arg function by fixing its second argument as the value 3. (See the September 2007 Code Craft article for more on standard function objects and bind2nd). The call to transform processes an array of four doubles, nums (declaration not shown), applies the composition of the three given functions, and prints the result to standard output—all in one statement. Summary // Listing 6 typedef function Fun; std::list funs; funs.push_back(bind2nd(divides (), 3.0)); funs.push_back(&f); // A plain double (*)(double) function funs.push_back(bind2nd(plus (), 1.0)); transform(nums, nums+4, ostream_iterator (cout," "), compose(funs.begin(),funs.end())); Listing 6 Let’s review what we have accomplished—we have created a reusable class for function composition, which can come in handy in data processing, and we have gained some experience in designing generic software. The final version of Composer is generic in that it can compose an arbitrary number of unary, single-valued functions or function objects of compatible types, and those functions can reside in an array or in any standard sequence container. Composer itself has reused the standard generic types and functions: accumulate, reverse_iterator, iterator_traits, and function. {end} tion of Composer also uses iterator_traits, a C++ feature that deduces the type to which an iterator points, as shown in listing 5. We are assuming that the type pointed to, Fun, is an instance of function, which happens to have a result_type member. We use this as the argument type since we expect the functions we compose to have the same argument and return type. To make things convenient for the user, we’ll create a function template that deduces the iterator type from its arguments: template Composer compose(Iter b, Iter e) { return Composer (b,e); } This allows users to embed calls to compose in other con- Chuck Allison developed software for twenty years before becoming a professor of computer science at Utah Valley State College. He was senior editor of the C/C++ Users Journal and is founding editor of The C++ Source. He is also the author of two C++ books and gives onsite training in C++, Python, and Design Patterns. Chuck is a technical editor for Better Software magazine. Sticky Notes For more on the following topic go to www.StickyMinds.com/bettersoftware. I Boost.function texts, as you can see in the sample code in listing 6, which composes two function objects along with a plain function pointer. The first line defines the type Fun as function , which matches anything that is callable with a single double argument and returns a double. The first function, which we create on the fly, divides its argu12 www.StickyMinds.com Is defining for reuse on your list of priorities? Do you routinely use generics? M Follow the link on the StickyMinds.com homepage to join the conversation. BETTER SOFTWARE JANUARY/FEBRUARY 2008 http://www.StickyMinds.com/bettersoftware http://StickyMinds.com http://www.StickyMinds.com
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.