Search code examples
c++streamstringstreamiostreamstreambuf

redirect std::cout to a custom writer


I want to use this snippet from Mr-Edd's iostreams article to print std::clog somewhere.

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>

int main()
{
    std::ostringstream oss;

    // Make clog use the buffer from oss
    std::streambuf *former_buff =
        std::clog.rdbuf(oss.rdbuf());

    std::clog << "This will appear in oss!" << std::flush;

    std::cout << oss.str() << '\\n';

    // Give clog back its previous buffer
    std::clog.rdbuf(former_buff);

    return 0;
}

so, in a mainloop, I will do something like

while (! oss.eof())
{
    //add to window text somewhere
}

Here's the ostringstream docs but I'm having trouble understanding the best way to do this. I have a method that displays the text, I just want to call it with any data in the ostringstream.

What is the easiest/best way to get anything sent to std::clog redirected to a method of my choice? is it as above, and fill in the while !eof part (not sure how), or is there a better way, say by overloading some 'commit' operator somewhere that calls my method? I'm loking for quick and easy, I really don't want to start defining sinks and such with boost iostreams as the article does - that stuff is way over my head.


Solution

  • I encourage you to look at Boost.IOStreams. It seems to fit your use-case nicely, and using it is surprisingly simple:

    #include <boost/iostreams/concepts.hpp> 
    #include <boost/iostreams/stream_buffer.hpp>
    #include <iostream>
    
    namespace bio = boost::iostreams;
    
    class MySink : public bio::sink
    {
    public:
        std::streamsize write(const char* s, std::streamsize n)
        {
            //Do whatever you want with s
            //...
            return n;
        }
    };
    
    int main()
    {
        bio::stream_buffer<MySink> sb;
        sb.open(MySink());
        std::streambuf * oldbuf = std::clog.rdbuf(&sb);
        std::clog << "hello, world" << std::endl;
        std::clog.rdbuf(oldbuf);
        return 0;
    }