Since iterators are identical to pointers in all essential ways, you can write the algorithms in the standard library in such a way as to allow both pointer and iterator arguments. For this reason, the implementation of copy( ) looks more like the following code.
template
void copy(Iterator begin, Iterator end, Iterator dest) {
while (begin != end)
*begin++ = *dest++;
}
Whichever argument type you use in the call, copy( ) assumes it properly implements the indirection and increment operators. If it doesn’t, you’ll get a compile-time error.
Predicates
At times, you might want to copy only a well-defined subset of one sequence to another, such as only those elements that satisfy a certain condition. To achieve this flexibility, many algorithms have alternate calling sequences that allow you to supply a
//: C06:CopyInts2.cpp
// Ignores ints that satisfy a predicate
#include
#include
#include
using namespace std;
// You supply this predicate
bool gt15(int x) {
return 15 < x;
}
int main() {
int a[] = {10, 20, 30};
const size_t SIZE = sizeof a / sizeof a[0];
int b[SIZE];
int* endb = remove_copy_if(a, a+SIZE, b, gt15);
int* beginb = b;
while (beginb != endb)
cout << *beginb++ << endl; // Prints 10 only
} ///:~.
The remove_copy_if( ) function template takes the usual range-delimiting pointers, followed by a predicate of your choosing. The predicate must be a pointer to function[79] that takes a single argument of the same type as the elements in the sequence, and it must return a bool. In this case, the function gt15 returns true if its argument is greater than 15. The remove_copy_if( ) algorithm applies gt15( ) to each element in the input sequence and ignores those elements when writing to the output sequence.
The following program illustrates yet another variation of the copy algorithm.
//: C06:CopyStrings2.cpp
// Replaces strings that satisfy a predicate
#include
#include
#include
#include
using namespace std;
// The predicate
bool contains_e(const string& s) {
return s.find('e') != string::npos;
}
int main() {
string a[] = {"read", "my", "lips"};
const size_t SIZE = sizeof a / sizeof a[0];
string b[SIZE];
string* endb =
replace_copy_if(a, a + SIZE, b, contains_e,
string("kiss"));
string* beginb = b;
while (beginb != endb)
cout << *beginb++ << endl;
} ///:~.
Instead of just ignoring elements that don’t satisfy the predicate, replace_copy_if( ) substitutes a fixed value for such elements when populating the output sequence. The output in this case is
kiss
my
lips
because the original occurrence of "read", the only input string containing the letter
The replace_if( ) algorithm changes the original sequence in place, instead of writing to a separate output sequence, as the following program shows.
//: C06:ReplaceStrings.cpp
// Replaces strings in-place
#include
#include
#include
#include
using namespace std;
bool contains_e(const string& s) {
return s.find('e') != string::npos;
}
int main() {
string a[] = {"read", "my", "lips"};
const size_t SIZE = sizeof a / sizeof a[0];
replace_if(a, a + SIZE, contains_e, string("kiss"));
string* p = a;
while (p != a + SIZE)
cout << *p++ << endl;
} ///:~
Stream iterators
Like any good software library, the Standard C++ Library attempts to provide convenient ways to automate common tasks. We mentioned in the beginning of this chapter that you can use generic algorithms in place of looping constructs. So far, however, our examples have still used an explicit loop to print their output. Since printing output is one of the most common tasks, you would hope for a way to automate that too.
That’s where
//: C06:CopyInts3.cpp
// Uses an output stream iterator
#include
#include
#include
#include
using namespace std;
bool gt15(int x) {
return 15 < x;
}
int main() {
int a[] = {10, 20, 30};
const size_t SIZE = sizeof a / sizeof a[0];
remove_copy_if(a, a + SIZE,
ostream_iterator
} ///:~.