insert a string in front of a istream in cpp

一笑奈何 提交于 2019-12-10 17:01:28

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!