Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::istream_iterator to read up to N values

Tags:

c++

If I know for certain that my input stream contains 10 values, I can read them with

std::copy_n(std::istream_iterator<T>(input), 10, output);

If I don't know how much values I have, I can read all of them with

std::copy(std::istream_iterator<T>(input), std::istream_iterator<T>(), output);

My problem is how to read up to 10 values. I'm trying to be robust against I/O errors here, but it appears that copy_n will try to read past the end of the input (it doesn't know that it should stop), and copy won't stop at 10 values. Do I have to roll my own copy_at_most?

(Well, there's apparently some confusion about copy_n anyway: std::istream_iterator<> with copy_n() and friends )

like image 502
MSalters Avatar asked Sep 16 '13 13:09

MSalters


2 Answers

Sadly, there is currently in general no way to limit the number of processed elements using STL algorithms. My personal view is that std::copy() should take two ranges both delimited by begin and end. If either end can't be reached the corresponding range would be unbounded. That is, if anything I would roll my own copy() algorithm like this:

template <typename InIt, typename OutIt>
std::pair<InIt, OutIt>
copy(InIt init, InIt inend, OutIt outit, OutIt outend) {
    for (; init != inend && outit != outend; ++init, ++outit) {
        *outit = *init;
    }
    return std::make_pair(init, outit);
}

To deal with the current iterator system, the comparison between output iterators actually can't be done. Thus, the comparison for output iterator actually requires a bit of template programming to make sure actual output iterators are never compared and, instead, true is returned. For all other iterator classes the above algorithm should just work (assuming I didn't introduce any typos).

like image 156
Dietmar Kühl Avatar answered Sep 23 '22 23:09

Dietmar Kühl


You could use copy_if and a counter - that unfortunately doesn't break early.

int count = 0;
std::copy_if(std::istream_iterator<T>(input), std::istream_iterator<T>(), output,
    [&]() { return ++count < 10; });

If you'd like to stick with algorithms (instead of plain for loop), I'd suggest you roll you own (I answered a similar question in the past.)

like image 31
jrok Avatar answered Sep 20 '22 23:09

jrok