First of all, the iterator is copyable, even though in the case of an InputIterator, the copy acts more like a move (specifically, after you increment any one copy of the iterator, you shouldn't dereference any other copy of it).
Nonetheless, there shouldn't be any problem with copying the iterator--in fact, most of the library (and a lot of other code) assumes that iterators are "lightweight" objects; copying them is cheap, so (for one obvious example) they're typically passed by value, not by reference.
So, a somewhat simplified stream iterator might look something like this:
template <class T>
class istream_iterator {
std::istream *is;
T data;
public:
istream_iterator(std::istream &is) : is(&is) { ++(*this); }
istream_iterator() : is(nullptr) { }
istream_iterator &operator++() { (*is) >> data; return *this; }
// So here's the post-increment: it just saves a copy of itself, then
// reads the next item (which increments the iterator), and finally
// returns the copied object, which will return the previously-read item
// from the stream when/if dereferenced.
istream_iterator operator++(int) {
// Note: this uses the compiler-generated copy constructor. Assuming
// a `T` is copy-constructible, this works fine--other than a T,
// we're only copying a pointer.
istream_iterator temp = *this;
(*is) >> data;
return temp;
}
T const &operator*() const { return data; }
bool operator !=(istream_iterator &end) { return (*is).good(); }
bool operator ==(istream_iterator &end) { return !(*is).good(); }
};
This "cheats" on a couple of fairly minor points--for example, two default-constructed iterators should compare equal to each other, which this doesn't bother to implement (and which virtually nobody ever uses or cares about). In normal use, you create one iterator from a stream, and default construct another. A comparison between the two should return true if and only if the first has reached the end of the input stream (or reading has failed for some reason, anyway). Likewise, this leaves out the implementation operator->
, and a few of the typedef
s required of a standard iterator type (value_type, traits_type, istream_type, etc.) None of these is relevant to the question at hand though (and all are a matter of adding the required code, not making any substantial changes to the code that's already here).
A quick demo of the code could look something like this:
int main() {
istream_iterator<char> i(std::cin), end;
while (i != end)
std::cout << *i++;
}
This will copy characters from standard input to standard output, skipping white space, because operator>>
skips whitespace by default (but you can eliminate that with noskipws
if you want).