问题
My problem is something like I want to append some string in front of a iostream. You can say in front of std::cin.
#include <iostream>
#include <string>
void print(std::istream & in){// function not to be modified
std::string str;
in >> str;
std::cout<< str << std::endl;
in >> str;
std::cout<< str << std::endl;
}
int main() {
std::string header = "hello ";
//boost::iostream::filtering_istream in(std::cin);
std::istream & in = std::cin;
//you may do someting here
//something like inserting characters into cin or something with buffers
print(in);
}
I want the implementation of the fuction such that if I provide input like
$ cat file.txt
help me to solve this.
$
$ ./a.out < file
hello
help
$
any kind of help is welcome. you may use boost::iostream to implement it.
回答1:
A stream is not a container. It is a flow of data. You cannot change data that has already floated away. The only exception is streams tied to block devices, in which you can seek around, e.g. fstream
- but even then you can only overwrite.
Instead, structure your code so that header
is consumed before the stream is consulted at all.
回答2:
You should avoid the issue. Just don't parse it all from the same stream if it isn't the same stream.
Low-Tech
A low-tech "solution" is to copy the stream to a stringstream, putting your "prefix" in the buffer first:
Live On Coliru
#include <iostream>
#include <string>
#include <sstream>
void print(std::istream &in) { // function not to be modified
std::string str;
while (in >> str)
std::cout << str << std::endl;
}
int main() {
std::string header = "hello ";
std::stringstream in;
in << header << std::cin.rdbuf();
print(in);
}
Given the input foo bar qux
prints:
hello
foo
bar
qux
High-Tech
You can always create a custom stream buffer that implements the behaviour you desire:
Live On Coliru
#include <iostream>
#include <sstream>
#include <vector>
template <typename B1, typename B2>
class cat_streambuf : public std::streambuf {
B1* _sb1;
B2* _sb2;
std::vector<char> _buf;
bool _insb1 = true;
public:
cat_streambuf(B1* sb1, B2* sb2) : _sb1(sb1), _sb2(sb2), _buf(1024) {}
int underflow() {
if (gptr() == egptr()) {
auto size = [this] {
if (_insb1) {
if (auto size = _sb1->sgetn(_buf.data(), _buf.size()))
return size;
_insb1 = false;
}
return _sb2->sgetn(_buf.data(), _buf.size());
}();
setg(_buf.data(), _buf.data(), _buf.data() + size);
}
return gptr() == egptr()
? std::char_traits<char>::eof()
: std::char_traits<char>::to_int_type(*gptr());
}
};
void print(std::istream &in) { // function not to be modified
std::string str;
while (in >> str)
std::cout << str << std::endl;
}
int main() {
std::stringbuf header("hello ");
cat_streambuf both(&header, std::cin.rdbuf());
std::istream is(&both);
print(is);
}
Which also prints
hello
foo
bar
qux
for the same input. This will definitely scale better for (very) large streams.
来源:https://stackoverflow.com/questions/49395583/insert-a-string-in-front-of-a-istream-in-cpp