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.
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.
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.