5

I'm using the cerr stream for my error output, but I also wanted to save any of this error output in a stringstream in memory.

I'm looking to turn this:

stringstream errorString;
cerr << " Something went wrong ";
errorString << " Something went wrong ";

Into

myErr << " Something went wrong ";

Where myErr is an instance of a class that stores this in a stringstream and also outputs to cerr.

Thanks for any help.

V.S.
  • 2,924
  • 4
  • 32
  • 43

5 Answers5

3

You could create the type of your myErr class like this:

class stream_fork
{
    std::ostream& _a;
    std::ostream& _b;

public:
    stream_fork( std::ostream& a, std::ostream& b)
        :   _a( a ),
            _b( b )
    {
    }

    template<typename T>
    stream_fork& operator<<( const T& obj )
    {
        _a << obj;
        _b << obj;
        return *this;
    }

    // This lets std::endl work, too!
    stream_fork& operator<<( std::ostream& manip_func( std::ostream& ) )
    {
        _a << manip_func;
        _b << manip_func;
        return *this;
    }
};

Usage:

stream_fork myErr( std::cerr, errorString );
myErr << "Error Message" << std::endl;
Timbo
  • 27,472
  • 11
  • 50
  • 75
  • Forgive my naivete, but with the use of templating, this would all have to be in a header file, yes? (Templates have always caused me problems!) – V.S. Sep 07 '11 at 14:47
  • Apparently it doesn't. And luckily this solution doesn't involve boost (which I'm not allowed to use). – V.S. Sep 07 '11 at 15:06
  • The implementation of the templated operator<< has to be visible from the point of instantiation, which is - in most cases - in a header file. It would be possible to move the implementation of the ctor and the other operator<< to a cpp file, if you wish to do so. – Timbo Sep 07 '11 at 15:07
  • In previous encounters with templates I'd end up with multiple copies of the function (each .o file would have its own or something), but this doesn't seem to have happened here! – V.S. Sep 07 '11 at 15:11
2

You can use Boost.IOStreams.

#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>
#include <sstream>

namespace io = boost::iostreams;

int main() {
    std::stringstream ss;
    io::tee_device<decltype(ss), decltype(std::cerr)> sink(ss, std::cerr);
    io::stream<decltype(sink)> stream(sink);
    stream << "foo" << std::endl;
    std::cout << ss.str().length() << std::endl;
    return 0;
}
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
1

Override operator<< in your MyErr class

MyErr& operator<< ( MyErr& myErr, std::string message)
{
    cerr << message;
    errorString << message; //Where errorString is a member of the MyErr class

    return myErr;
}

Then where you want to log the error:

int main()
{
    MyErr myErr;
    myErr << " Something went wrong. ";

    return 0;
}

You might want to make MyErr a singleton class so that everything written to errorString is in one place.

Daniel
  • 6,595
  • 9
  • 38
  • 70
1

Use Boost tee.

jason
  • 236,483
  • 35
  • 423
  • 525
  • I was typing out a bit on howto write your own tee class. I should have remembered boost had one. Stupid kits. – KitsuneYMG Sep 07 '11 at 14:33
0

You need to subclass streambuf and declare myErr as an ostream that uses your subclass. Make the input functions do nothing and then have the output functions copy out to whatever streams you need.

I had a class that did something similar 12 years ago, but have lost track of it. I haven't been able to find a good example, but the docs for streambuf could be a starting point. Focus on the protected output functions.

Mike DeSimone
  • 41,631
  • 10
  • 72
  • 96