Search code examples
c++iostreamfstreamcoutofstream

Is there a way to create a common output stream object to print on the console and to a file in c++?


I am writing a code where I have to print the same data on the console and to a file. Is there a way to populate a common output stream object and then display it on console using cout and export it to a file, using fstream and iostream libraries?


Solution

  • Sure. You'd just create a suitable stream buffer which probably stores to other stream buffers it writes to internally. Using this stream buffer you'd then create an std::ostream you are writing to.

    For example, here is a simple implementation of this approach:

    #include <streambuf>
    #include <ostream>
    
    class teebuf
        : public std::streambuf
    {
        std::streambuf* sb1_;
        std::streambuf* sb2_;
    
        int overflow(int c) {
            typedef std::streambuf::traits_type traits;
            bool rc(true);
            if (!traits::eq_int_type(traits::eof(), c)) {
                traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
                    && (rc = false);
                traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
                    && (rc = false);
            }
            return rc? traits::not_eof(c): traits::eof();
        }
        int sync() {
            bool rc(false);
            this->sb1_->pubsync() != -1 || (rc = false);
            this->sb2_->pubsync() != -1 || (rc = false);
            return rc? -1: 0;
        }
    public:
        teebuf(std::streambuf* sb1, std::streambuf* sb2)
            : sb1_(sb1), sb2_(sb2) {
        }
    };
    
    class oteestream
        : private virtual teebuf
        , public std::ostream {
    public:
        oteestream(std::ostream& out1, std::ostream& out2)
            : teebuf(out1.rdbuf(), out2.rdbuf())
            , std::ostream(this) {
            this->init(this);
        }
    };
    
    #include <fstream>
    #include <iostream>
    
    int main()
    {
        std::ofstream fout("tee.txt");
        oteestream    tee(fout, std::cout);
        tee << "hello, world!\n";
    }