Невозможно изменить istream_iterator
таким образом, потому что он не знает ни о новых строках, ни даже о символах. Он знает только о int64
(или о том, с каким типом вы его создали) и о том, закончился ли поток или произошел сбой (когда он вернет false
на operator bool()
).
Это означает, что наша точка настройки должна быть фактическим потоком.
Объект потока на самом деле является просто оболочкой вокруг std::basic_streambuf
. Streambuf будет выплевывать символы, пока не найдет EOF
. Вы можете просто настроить его так, чтобы он возвращал EOF
, как только он обнаружил новую строку, тогда поток временно будет рассматривать это как конец потока.
Сделать это легко: объект streambuf доступен через функцию члена rdbuf()
. Вы можете просто заменить буфер на свой, используя эту функцию. Чтобы продолжить чтение после новой строки, когда вы закончите, вы можете просто вернуть оригинал std::basic_streambuf
обратно в поток.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <streambuf>
#include <vector>
// This is our custom std::basic_streambuf object.
// We chose the underflow function as our point of customization, because
// it is there that the action is happening: it is this function that
// that is responsible for reading more data from the stream.
class newline_buf : public std::streambuf {
std::streambuf* src;
char ch; // single-byte buffer
protected:
int underflow() {
if( (ch= src->sbumpc()) == '\n') {
return traits_type::eof(); // return EOF on new line.
}
setg(&ch, &ch, &ch+1); // make one read position available
return ch; // may also return EOF by the regular means
}
public:
newline_buf(std::streambuf* buf) : src(buf) {
setg(&ch, &ch+1, &ch+1); // buffer is initially full
}
};
int main() {
// testing with a stringstream to make things easier to reproduce.
// Should work fine with any type of input stream.
std::istringstream iss(R"(12345 12345 12345
67890 67890 67890)");
// We store the original rdbuf so we can recover it later.
auto original_rdbuf = iss.rdbuf();
newline_buf buf(original_rdbuf);
iss.basic_ios::rdbuf(&buf);
// Do the copy and then recover the original rdbuf
std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::ostream_iterator<int>(std::cout, " "));
iss.basic_ios::rdbuf(original_rdbuf);
// You can try doing a new copy, just to convince yourself that the stream is still in a valid state.
//std::copy(std::istream_iterator<int>(iss), std::istream_iterator<int>(), std::ostream_iterator<int>(std::cout, " "));
}