Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
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 stream iterators come in. A stream iterator uses a stream as either an input or an output sequence. To eliminate the output loop
in the CopyInts2.cpp program, for instance, you can do something like
the following:
//: C06:CopyInts3.cpp
// Uses an output stream iterator.
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
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<int>(cout,
"\n"), gt15);
} ///:~
In this example we ve replaced the output sequence b
in the third argument of remove_copy_if( ) with an output
stream iterator, which is an instance of the ostream_iterator class template declared in the <iterator> header. Output stream iterators overload their copy-assignment
operators to write to their stream. This particular instance of ostream_iterator
is attached to the output stream cout. Every time remove_copy_if( )
assigns an integer from the sequence a to cout through this
iterator, the iterator writes the integer to cout and also automatically
writes an instance of the separator string found in its second argument, which
in this case contains the newline character.
It is just as easy to write to a file by providing an output
file stream, instead of cout:
//: C06:CopyIntsToFile.cpp
// Uses an output file stream iterator.
#include <algorithm>
#include <cstddef>
#include <fstream>
#include <iterator>
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];
ofstream outf("ints.out");
remove_copy_if(a, a + SIZE,
ostream_iterator<int>(outf,
"\n"), gt15);
} ///:~
An input stream iterator allows an algorithm to get
its input sequence from an input stream. This is accomplished by having both
the constructor and operator++( ) read the next element from the
underlying stream and by overloading operator*( ) to yield the
value previously read. Since algorithms require two pointers to delimit an
input sequence, you can construct an istream_iterator in two ways, as you can see in the program that follows.
//: C06:CopyIntsFromFile.cpp
// Uses an input stream iterator.
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include "../require.h"
using namespace std;
bool gt15(int x) { return 15 < x; }
int main() {
ofstream ints("someInts.dat");
ints << "1 3 47 5 84 9";
ints.close();
ifstream inf("someInts.dat");
assure(inf, "someInts.dat");
remove_copy_if(istream_iterator<int>(inf),
istream_iterator<int>(),
ostream_iterator<int>(cout,
"\n"), gt15);
} ///:~
The first argument to replace_copy_if( ) in this
program attaches an istream_iterator object to the input file stream
containing ints. The second argument uses the default constructor of the
istream_iterator class. This call constructs a special value of istream_iterator
that indicates end-of-file, so that when the first iterator finally encounters
the end of the physical file, it compares equal to the value istream_iterator<int>( ),
allowing the algorithm to terminate correctly. Note that this example avoids
using an explicit array altogether.
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |