Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

output to two streams via a single ostream?

0 views
Skip to first unread message

Steve Brecher

unread,
Sep 24, 1996, 3:00:00 AM9/24/96
to

I have a program whose normal output is to cout. Operator<< is overloaded
for various classes in the form

ostream& operator<< (ostream& os, class_type& object);

and there are various cout << ... statements which output objects of
built-in and user-defined types.

I've been trying without success to think of a relatively simple way to
mirror selected output to a file -- a console log of selected program
output -- without duplicating the output statements and changing the
target ostream in the duplicates. Thus, where lout is an ofstream opened
to the log file, instead of

cout << this << that << other;
lout << this << that << other;

I'd like to write something like

my_dual_ostream << this << that << other;

I can't think of a way to accomplish this without reimplementing
IOStreams. But I've been using C++ for only a few months, and am hesitant
to conclude, without asking, that it can't be done.

--
st...@brecher.reno.nv.us (Steve Brecher)

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Friedrich Knauss

unread,
Sep 25, 1996, 3:00:00 AM9/25/96
to

In article <529ir6$s...@netlab.cs.rpi.edu>,

Steve Brecher <st...@brecher.reno.nv.us> wrote:
>I've been trying without success to think of a relatively simple way to
>mirror selected output to a file -- a console log of selected program
>output -- without duplicating the output statements and changing the
>target ostream in the duplicates. Thus, where lout is an ofstream opened
>to the log file, instead of

I've solved this problem by creating a streambuffer class which keeps
a list<ostream *>. On overflow() and sync() it dumps its contents to
each of the ostreams in the list, followed by a flush. Icky, but it
seems to do the job.

The associated ostream class has Add(ostream &) and Remove(ostream &)
member functions for adding and removing streams. To prevent infinite
recursion, it does not allow itself to be added.

This class then solves your problem, and it may handle other similiar
problems (like wanting to echo to a number of different sockets), plus
it also makes a very nice bit bucket if no streams are attached.

--
-- fri...@qualcomm.com
-- Pain is temporary, glory is forever.
--

Herb Sutter

unread,
Sep 25, 1996, 3:00:00 AM9/25/96
to

On 24 Sep 1996 17:12:06 -0400, st...@brecher.reno.nv.us (Steve
Brecher) wrote:
[wants to 'tee' streamed output]

>instead of
>
>cout << this << that << other;
>lout << this << that << other;
>
>I'd like to write something like
>
>my_dual_ostream << this << that << other;

You might try the following (this is just a quick hack for
demonstration purposes):

/* op<< is global because my compiler doesn't support member
templates, and the _targets list is public because my
compiler also doesn't let me make the global op<< a friend */

class multiway_ostream
{
public:
void add( ostream& os ) { _targets.push_back(&os); };
list<ostream*> _targets;
};

template<class T>
multiway_ostream& operator<<(multiway_ostream& mos, const T& t)
{
for( list<ostream*>::iterator i = mos._targets.begin();
i != mos._targets.end();
++i )
{
*(*i) << t;
}
return mos;
}

Now you can multicast to as many ostreams as you want:

int main( int argc, char* argv[])
{
ofstream of1( "test1.out" );
ofstream of2( "test2.out" );

multiway_ostream mos;
mos.add( cout );
mos.add( of1 );
mos.add( of2 );

mos << "Hello" << " world" << endl; // goes to all three ostreams

return 0;
}

Note that I deliberately didn't inherit from ostream because I didn't
want a multiway_ostream passed around and used as an ostream. Without
spending some time looking at ostream's definition, I'm not sure that
all of the inherited state and functions would be appropriate. It's
fine for this use, though.

---
Herb Sutter (he...@cntc.com)

Current Network Technologies Corp.
3100 Ridgeway, Suite 42, Mississauga ON Canada L5L 5M5
Tel 416-805-9088 Fax 905-608-2611

J. Kanze

unread,
Sep 26, 1996, 3:00:00 AM9/26/96
to

st...@brecher.reno.nv.us (Steve Brecher) writes:

> I have a program whose normal output is to cout. Operator<< is overloaded
> for various classes in the form
>
> ostream& operator<< (ostream& os, class_type& object);
>
> and there are various cout << ... statements which output objects of
> built-in and user-defined types.
>

> I've been trying without success to think of a relatively simple way to
> mirror selected output to a file -- a console log of selected program
> output -- without duplicating the output statements and changing the
> target ostream in the duplicates. Thus, where lout is an ofstream opened

> to the log file, instead of


>
> cout << this << that << other;
> lout << this << that << other;
>
> I'd like to write something like
>
> my_dual_ostream << this << that << other;
>

> I can't think of a way to accomplish this without reimplementing
> IOStreams. But I've been using C++ for only a few months, and am hesitant
> to conclude, without asking, that it can't be done.

It's actually fairly easy: use a forwarding streambuf.

In this case, derive a streambuf which takes to other streambufs as
parameters, and forwards the characters to both of them. The only
potential problem is error handling: what do you return if there is an
error from one of the streambufs, but not the other. In your case,
however, I presume that the console output is the principal output, the
other is just for convenience, so you should probably return the status
of the console streambuf.

--
James Kanze (+33) 88 14 49 00 email: ka...@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs Bourgeois, 67000 Strasbourg, France
Conseils en informatique industrielle --
-- Beratung in industrieller Datenverarbeitung

J. Kanze

unread,
Oct 3, 1996, 3:00:00 AM10/3/96
to

fkn...@qualcomm.com (Friedrich Knauss) writes:

> In article <529ir6$s...@netlab.cs.rpi.edu>,
> Steve Brecher <st...@brecher.reno.nv.us> wrote:

> >I've been trying without success to think of a relatively simple way to
> >mirror selected output to a file -- a console log of selected program
> >output -- without duplicating the output statements and changing the
> >target ostream in the duplicates. Thus, where lout is an ofstream opened
> >to the log file, instead of
>

> I've solved this problem by creating a streambuffer class which keeps
> a list<ostream *>. On overflow() and sync() it dumps its contents to
> each of the ostreams in the list, followed by a flush. Icky, but it
> seems to do the job.
>
> The associated ostream class has Add(ostream &) and Remove(ostream &)
> member functions for adding and removing streams. To prevent infinite
> recursion, it does not allow itself to be added.

This sounds like a nice generalization of what I suggested, but what do
you return from overflow?

J. Kanze

unread,
Oct 3, 1996, 3:00:00 AM10/3/96
to
0 new messages