Выбрать главу

const LessThanComparable& max(const LessThanComparable& a,   const LessThanComparable& b); const T& max(const T& a, const T& b,   BinaryPredicate binary_pred);

Exactly like min( ), but returns the greater of its two arguments.

void swap(Assignable& a, Assignable& b); void iter_swap(ForwardIterator1 a, ForwardIterator2 b);

Exchanges the values of a and b using assignment. Note that all container classes use specialized versions of swap( ) that are typically more efficient than this general version.

The iter_swap( ) function swaps the values that its two arguments reference.

Creating your own STL-style algorithms

Once you become comfortable with the STL algorithm style, you can begin to create your own generic algorithms. Because these will conform to the conventions of all the other algorithms in the STL, they’re easy to use for programmers who are familiar with the STL, and thus they become a way to "extend the STL vocabulary.".

The easiest way to approach the problem is to go to the <algorithm> header file, find something similar to what you need, and pattern your code after that.[90] (Virtually all STL implementations provide the code for the templates directly in the header files.)

Now that you’re comfortable with the ideas of the various iterator types, the actual implementation is quite straightforward. You can imagine creating an entire additional library of your own useful algorithms that follow the format of the STL.

If you take a close look at the list of algorithms in the standard C++ library, you might notice a glaring omission: there is no copy_if( ) algorithm. Although it’s true that you can accomplish the same thing with remove_copy_if( ), this is not quite as convenient because you have to invert the condition. (Remember, remove_copy_if( ) only copies those elements that don’t match its predicate, in effect removing those that do.) You might be tempted to write a function object adapter that negates its predicate before passing it to remove_copy_if( ), by including a statement something like this:

// Assumes pred is the incoming condition

replace_copy_if(begin, end, not1(pred));

This seems reasonable, but when you remember that you want to be able to use predicates that are pointers to raw functions, you see why this won’t work—not1 expects an adaptable function object. The only solution is to write a copy_if( ) algorithm from scratch. Since you know from inspecting the other copy algorithms that conceptually you need separate iterators for input and output, the following example will do the job.

//: C06:copy_if.h

// Roll your own STL-style algorithm

#ifndef COPY_IF_H

#define COPY_IF_H

template<typename ForwardIter,

  typename OutputIter, typename UnaryPred>

OutputIter copy_if(ForwardIter begin, ForwardIter end,

  OutputIter dest, UnaryPred f) {

  while(begin != end) {

    if(f(*begin))

      *dest++ = *begin;

    ++begin;

  }

  return dest;

}

#endif // COPY_IF_H ///:~

Summary

The goal of this chapter was to give you a practical understanding of the algorithms in the Standard Template Library. That is, to make you aware of and comfortable enough with the STL that you begin to use it on a regular basis (or, at least, to think of using it so you can come back here and hunt for the appropriate solution). It is powerful not only because it’s a reasonably complete library of tools, but also because it provides a vocabulary for thinking about problem solutions and because it is a framework for creating additional tools.

Although this chapter did show some examples of creating your own tools, we did not go into the full depth of the theory of the STL that is necessary to completely understand all the STL nooks and crannies to allow you to create tools more sophisticated than those shown here. This was in part because of space limitations, but mostly because it is beyond the charter of this book; our goal here is to give you practical understanding that will affect your day-to-day programming skills.

A number of books are dedicated solely to the STL (these are listed in the appendices), but we especially recommend Matthew H. Austern’s Generic Programming and the STL (Addison-Wesley, 1999) and Scott Meyers’s Effective STL (Addison-Wesley, 2002).

Exercises

             4.             Create a generator that returns the current value of clock( ) (in <ctime>). Create a list<clock_t>, and fill it with your generator using generate_n( ). Remove any duplicates in the list and print it to cout using copy( ).

             4.             Using transform( ) and toupper( ) (in <cctype>), write a single function call that will convert a string to all uppercase letters.

             5.             Create a Sum function object template that will accumulate all the values in a range when used with for_each( ).

             6.             Write an anagram generator that takes a word as a command-line argument and produces all possible permutations of the letters.

             7.             Write a "sentence anagram generator" that takes a sentence as a command-line argument and produces all possible permutations of the words in the sentence. (It leaves the words alone and just moves them around.)

             8.             Create a class hierarchy with a base class B and a derived class D. Put a virtual member function void f( ) in B such that it will print a message indicating that B’s f( ) was called, and redefine this function for D to print a different message. Create a vector<B*>, and fill it with B and D objects. Use for_each( ) to call f( ) for each of the objects in your vector.

             9.             Modify FunctionObjects.cpp so that it uses float instead of int.

        10.             Modify FunctionObjects.cpp so that it templatizes the main body of tests so you can choose which type you’re going to test. (You’ll have to pull most of main( ) out into a separate template function.)

         11.             Write a program that takes an integer as a command line argument and finds all of its factors.

         12.             Write a program that takes as a command-line argument the name of a text file. Open this file and read it a word at a time (hint: use >>). Store each word into a vector<string>. Force all the words to lowercase, sort them, remove all the duplicates, and print the results.