Search code examples
c++c++11vectorostream

How to write vector of ostreams in C++ which takes in all the different output streams like cout, ostringstream and ofstream


I am trying to implement a logger which can be registered with multiple streams like ostringstream, ofstream etc. I tried to implement the function like this

void register_stream(std::ostream& a);

The vector is as follows

std::vector<std::ostream> streams;

The register stream and operator overloading is as follows

void logger::register_stream(std::ostream &a)`

{

    streams.push_back(a);

}

template <typename T>

void logger::operator<<(T const& value)

{

    for (auto stream : streams)

    {

        (stream) << value;

    }

}

I am trying to implement a logger to write to all registered streams on a single operator "<<" call.

The following is the invocation code:

std::ostringstream os;
    std::ofstream f;
    logger l;
    l.register_stream(f);
    l.register_stream(os);
    l << "log this";

I am getting an error:

C2280: std::basic_ostream<char,std::char_traits<char>>::basic_ostream(const std::basic_ostream<char,std::char_traits<char>> &): attempting to reference a deleted function

Any help would be much appreciated.


Solution

  • You can't store copies of your streams, they are not copiable. You have to store std::reference_wrappers or pointers instead.

    class logger {
        std::vector<std::reference_wrapper<std::ostream>> streams;
    public:
        void register_stream(std::ostream &stream) {
            streams.emplace_back(stream);
        }
    
        template <typename T>
        void operator<<(T const &value) {
            for (auto &stream : streams) { // note the '&'
                stream.get() << value;
            }
        }
    };
    

    or if you want to be able to chain your calls like l << "log" << " this";:

        template <typename T>
        logger & operator<<(T const &value) {
            for (auto &stream : streams) {
                stream.get() << value;
            }
            return *this;
        }