Article 36: Understand the correct implementation of copy_if
STL has many interesting aspects, one of which is an algorithm with 11 names including "copy:
Copy |
Copy_backward |
Replace_copy |
Reverse_copy |
Replace_copy_if |
Unique_copy |
Remove_copy |
Rotate_copy |
Remove_copy_if |
Partial_sort_copy |
Unintialized_copy |
|
But none of them are copy_if. This means you can replace_copy_if, You Can remove_copy_if, You Can copy_backward or reverse_copy, But if you simply want to copy elements that meet a certain predicate in a range, you can only do it yourself.
For example, suppose you have a function to determine whether a widget is defective:
bool isDefective(const Widget& w);
In addition, you want to write all defective widgets in a vector to cerr. If copy_if exists, you can simply do this:
Vector <widget> widgets;... copy_if (Widgets. Begin (), Widgets. End (),//This cannot be compiled:Ostream_iterator <widget> (cerr, "/N "),//There is no copyif in STLIsdefective );
Ironically, copy_if is part of the original hp stl, which forms the foundation of STL, and STL is now part of the standard C ++ library. Some quirks make history interesting. copy_if became one of the items abandoned in the cut room when filtering out some small and manageable items from hp stl for the standard.
In the C ++ programming language [7], stroustrup emphasizes that copy_if writing is insignificant and he is right, but that doesn't mean that it is easy to implement the correct things. For example, here is a reasonable view of copy_if, which many people (including me) once know:
Template <typename iterator, // an incorrect typename outputiterator, // copy_if implements typename predicate> outputiterator copy_if (begin in, end, outputiterator destbegin, predicate P) {return remove_copy_if (begin, end, destbegin, not1 (p ));}
This method is based on this point of view-although STL does not allow you to say "copy everything with the limit to true ", but it does make you say "copying everything except the limit type is not true ". To implement copy_if, it seems that all we need to do is add not1 before the compile type we want to pass to copy_if, and then pass the result into remove_copy_if. The result is the above Code.
If the above reason is valid, we can use this method to write defective widgets:
copy_if(widgets.begin(), widgets.end(), // well-intentioned code ostream_iterator<Widget>(cerr, "/n"), // that will not compile isDefective);
Your STL platform will be hostile to this code because it tries to apply not1 to isdefective (this application appears inside copy_if ). As Clause 41 tries to clarify, not1 cannot be directly applied to a function pointer, and the function pointer must be passed to ptr_fun first. To call this copy_if implementation, you must pass not only a function object, but alsoAdaptionFunction object. This is simple enough, but it is not necessary for users who want to become STL algorithm users. Standard STL algorithms never require that their imitation functions be adaptive, and copy_if should not. The above implementation is good, but not good enough.
This is the correct and insignificant Implementation of copy_if:
Template <typename iterator, // A copy_if typename outputiterator, // correctly implements typename predicate> extends copy_if (begin, begin end, outputiterator destbegin, predicate p) {While (begin! = END) {If (P (* begin) * destbegin ++ = * begin; ++ begin;} return destbegin ;}
Tell you how useful copy_if is. In addition, the new STL programmer tends to expect that it should exist in any case, so the good way is to take copy_if -- the correct one! -- Put it in your local STL-related tool library and use it whenever appropriate.