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

Overloading << for cross-platform use.

10 views
Skip to first unread message

David W. Coppit

unread,
Apr 1, 1997, 3:00:00 AM4/1/97
to

I'm working with some code that I'm compiling for Windows and Unix. In
Unix, simply saying "cout << ..." works great, but in Windows I have to
append the string to a class variable, update the variable, redraw the
screen, etc. One thing I could do is to #ifdef two implementations at
every point in the program that I output information, but that is a
horrible violation of encapsulation.

What I would like to do is to *redefine* what happens when one tries to
write to a stream, so that the output is sent to a window. Unfortunately,
when I try to do something like

ostream& operator << (const char* string) {
window->output_var = string;
window->UpdateData(FALSE);
window->Invalidate();
window->UpdateWindow();

return os;
}

The compiler complains about ambiguity. From what I understand, operator
<< and operator >> can not be members of a class or struct, so I can't
scope them (and I don't trust namespaces yet).

I could write my own function for output, but this would require
widespread changes to the original code, plus I would lose the syntactic
sugar of "output << first << second << third".

Any suggestions?

Thanks,
David

-------------------------------------------------------------------------
David Coppit - Graduate Student cop...@cs.virginia.edu
The University of Virginia http://www.cs.virginia.edu/~dwc3q
"Shine on you crazy diamond." - Pink Floyd


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


Dietmar Kuehl

unread,
Apr 2, 1997, 3:00:00 AM4/2/97
to

Hi,
David W. Coppit (dw...@mamba.cs.virginia.edu) wrote:

: I'm working with some code that I'm compiling for Windows and Unix. In

: Unix, simply saying "cout << ..." works great, but in Windows I have to
: append the string to a class variable, update the variable, redraw the
: screen, etc.

Although I know it is not covered in the C++ FAQ file, I think this
question is a FAQ... Here is the answer:

The classes 'istream' and 'ostream' (aka 'basic_istream' and
'basic_ostream') are merely convenient frontends to an actual
abstraction from the external representation. This abstraction uses the
base class 'streambuf' (aka 'basic_streambuf') as interface. If you
need a new external representation, you just derive from 'streambuf' a
class which overrides the relevent virtual functions. For output these
are normally 'sync()' and 'overflow()' plus, to increase performance,
'xsputn()'.

For example, the implementation of the function 'xsputn()' of a class
'windowbuf' which writes to some GUI window might look like this:

streamsize windowbuf::xsputn(char const *str, streamsize n)
{
if (epptr() - pptr() > n) // if the buffer has sufficient space
{
strncpy(pptr(), str, n); // put the string into the buffer
pbump(n); // ... and adjust the buffer
}
else // otherwise write the string directly
{
if (pbase() != pptr()) // if the buffer is not empty
sync(); // empty the current buffer

// Now sent the string to the window (using an interface which is
// apparently foobar; I don't have any documentation for it, though):
window->output_var = str;


window->UpdateData(FALSE);
window->Invalidate();
window->UpdateWindow();
}
}

This stream uses the window functions to sent the string. Another
stream, eg. one sending output to a file, would use a different
approach. For example, the system function 'write()' (this is POSIX, on
other systems something similar is used) may be used to write things to
a file the external representation is actually a file.

For a more complete example of a stream buffer writing to a GUI window,
more precisely to a Motif Text Widget, have a look at
<http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/>.

: One thing I could do is to #ifdef two implementations at

: every point in the program that I output information, but that is a
: horrible violation of encapsulation.

Indeed, this is a maintainance nightmare which would become even worse
if you add another system. Instead deriving from 'streambuf' give a
clean solution which needs only changes in few points in the code,
namely where there corresponding 'ostream's are set up.

: What I would like to do is to *redefine* what happens when one tries to

: write to a stream, so that the output is sent to a window. Unfortunately,
: when I try to do something like

: ostream& operator << (const char* string) {
: window->output_var = string;
: window->UpdateData(FALSE);
: window->Invalidate();
: window->UpdateWindow();

: return os;
: }

While this is reasonably easy to do for 'char const *' it is already
more complex eg. for a 'double' and is practically impossible to do for
a user defined type. Using the approach which is intended for this
situation, namely derivation from 'streambuf', is less complex and
works...
--
<mailto:dietma...@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly pessimistic

Jim Mitchell

unread,
Apr 2, 1997, 3:00:00 AM4/2/97
to

> ostream& operator << (const char* string) {
> window->output_var = string;
> window->UpdateData(FALSE);
> window->Invalidate();
> window->UpdateWindow();
>
> return os;
> }
The style police will probably arrest me, but I'm doing something
similar by using
Message::operator>>(...);

You could write:
window& window::operator<< (const char* string) {
this->output_var = string;
// etc...
return *this;
}

The reason why ostream& operator<< can't be a member function of a class
you define is that it is applies to _ostreams_! If you're applying the
function to your own class, then go ahead and make it a member function
and forget about the ostream implementation. Of course this means that
your class's operator<< must be overloaded for each of the types it
needs to accept, but it works for me.

Watch out for the style police, though. ;)

:)

Jim

Dietmar Kuehl

unread,
Apr 2, 1997, 3:00:00 AM4/2/97
to

Hi,
Jim Mitchell (jmi...@clark.net) wrote:
: > ostream& operator << (const char* string) {

: > window->output_var = string;
: > window->UpdateData(FALSE);
: > window->Invalidate();
: > window->UpdateWindow();
: >
: > return os;
: > }
: The style police will probably arrest me, but I'm doing something
: similar by using
: Message::operator>>(...);

It is not that much the "style police" but yourself creating artificial
problems... Of course, you can use this approach but there are some
problems:

- A 'Message' IS-NOT-A 'ostream'. Thus, you cannot use a 'Message'
where an 'ostream' is required.
- To reuse user defined inserters, you have to implement some template
stuff and handle individual insertions.
- To make the interface similar to the interface of 'ostream', you have
basically to reimplement the class 'ostream'.
- You cannot make existing streams like 'cerr' write to your 'Message'
facility, unless you wrap a class derived from 'streambuf' around
your 'Message' class.

But the IOStream library is designed for extensibility, at least to
support new external representations. This is done by just deriving
from 'streambuf' and initializing an 'ostream' with an object of this
new 'streambuf' class (see my other article in this thread and the
WWW-page mentioned there for more details). This takes just a some
lines and provides a solid solution which fits well into the standard
part of the IOStream library.


--
<mailto:dietma...@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly
pessimistic

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Marcelo Cantos

unread,
Apr 4, 1997, 3:00:00 AM4/4/97
to

"David W. Coppit" <dw...@mamba.cs.virginia.edu> writes:

> What I would like to do is to *redefine* what happens when one tries to
> write to a stream, so that the output is sent to a window. Unfortunately,
> when I try to do something like

What you want is not trivial and has more to do with trapping system
events at the OS level than redefining stream behaviour at the C++
level.

What you need to do is define a new stream class. Thus you could
write:

class winstream : virtual public ios, public istream { // ...


window w;
// ...
winstream output(w);

output << first << second << third << flush;

or:

winstream(w) << "Hello" << flush;

I won't kid you though, this is not a trivial undertaking.


--
______________________________________________________________________
Marcelo Cantos, Research Assistant __/_ mar...@mds.rmit.edu.au
Multimedia Database Systems Group, RMIT / _ Tel 61-3-9282-2497
723 Swanston St, Carlton VIC 3053 Aus/ralia ><_> Fax 61-3-9282-2490
Acknowledgements: errors - me; wisdom - God; funding - RMIT

James Kanze

unread,
Apr 4, 1997, 3:00:00 AM4/4/97
to

ku...@horn.informatik.uni-konstanz.de (Dietmar Kuehl) writes:

|> David W. Coppit (dw...@mamba.cs.virginia.edu) wrote:
|>
|> : I'm working with some code that I'm compiling for Windows and Unix. In
|> : Unix, simply saying "cout << ..." works great, but in Windows I have to
|> : append the string to a class variable, update the variable, redraw the
|> : screen, etc.
|>
|> Although I know it is not covered in the C++ FAQ file, I think this
|> question is a FAQ... Here is the answer:
|>
|> The classes 'istream' and 'ostream' (aka 'basic_istream' and
|> 'basic_ostream') are merely convenient frontends to an actual
|> abstraction from the external representation.

IMHO, slightly more than nits...

The classes istream and ostream are more than just "convenient
frontends"; they encapsulate an important abstraction (that of formatted
text) in their own right. In a very real sense, it is they that
encapsulate the abstraction of an "external representation", not the
streambuf class. (The abstraction encapsulated in the streambuf class
and its derivatives is that of a data sink and source.)

One thing that is common to the abstractions of both streambuf and
[io]stream is the concept of a stream; both deal with linear streams of
data: one dimensional sequences. As such, they are not a particularly
appropriate abstraction for a window, which is two dimensional and has
direct access.

>From a conceptual point of view, I find it normal, and even preferable,
that the functionality of generating the text stream to be displayed,
and actually displaying it, are separated. In the first, the
abstraction is a stream (of text characters); in the second, the
resulting text string is treated as a single object. I would thus
expect that building the string and displaying it involve different
actions on different objects. (Typically, the string will be built
using wostringstream or ostringstream; one of the overloaded display
functions of the window object will probably take a "string" as the
object to be displayed.)

|> This abstraction uses the
|> base class 'streambuf' (aka 'basic_streambuf') as interface. If you
|> need a new external representation, you just derive from 'streambuf' a
|> class which overrides the relevent virtual functions. For output these
|> are normally 'sync()' and 'overflow()' plus, to increase performance,
|> 'xsputn()'.

I'm skeptical of using the streambuf abstraction for managing a window.
On one hand, it seems too limiting; there are too many things you can do
with a window that have no place in the abstraction. On the other hand,
it seems to leave to many of the details exposed; do you have to flush
to ensure that the data appear, or does this happen automatically at
some particular point in time, or...

[example code deleted...]


|> For a more complete example of a stream buffer writing to a GUI window,
|> more precisely to a Motif Text Widget, have a look at
|> <http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/>.

I've not looked at the code, and I'm not that familiar with X-Windows
programming either. But a Text Widget is not a window, as far as I
know. It is a special type of (sub-)object which is (or may be) part of
a window. It is quite possible that the streambuf abstraction be
appropriate for this particular type of object. (It's also possible
that it's not; I don't know enough to say. But the word "text" in the
name suggests to me that it might be.)

|> : One thing I could do is to #ifdef two implementations at
|> : every point in the program that I output information, but that is a
|> : horrible violation of encapsulation.
|>
|> Indeed, this is a maintainance nightmare which would become even worse
|> if you add another system. Instead deriving from 'streambuf' give a
|> clean solution which needs only changes in few points in the code,
|> namely where there corresponding 'ostream's are set up.

The problem is that when outputting to a file and when outputting to a
window, you are not outputting the same information. Outputting to a
window requires MORE information (where, etc.).

|> : What I would like to do is to *redefine* what happens when one tries to

|> : write to a stream, so that the output is sent to a window. Unfortunately,
|> : when I try to do something like
|>

|> : ostream& operator << (const char* string) {
|> : window->output_var = string;
|> : window->UpdateData(FALSE);
|> : window->Invalidate();
|> : window->UpdateWindow();
|>
|> : return os;
|> : }
|>

|> While this is reasonably easy to do for 'char const *' it is already
|> more complex eg. for a 'double' and is practically impossible to do for
|> a user defined type. Using the approach which is intended for this
|> situation, namely derivation from 'streambuf', is less complex and
|> works...

Except that you somehow have to define *when* you do the update; every
character, or only on explicit flush, or... (And this is neglecting the
problems of "where", "what color and font", etc.)

IMHO, this approach (deriving from streambuf) is only appropriate for
windows which, once created, act like streams. (A window which simply
inserts output text at the end, as lines, and scrolls up as necessary,
might be an example.)

--
James Kanze home: ka...@gabi-soft.fr +33 (0)1 39 55 85 62
office: ka...@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --

John McAleely

unread,
Apr 4, 1997, 3:00:00 AM4/4/97
to

I think you need to derive from ostream:

class winunixos : public ostream {
...
};

Then declare a new output stream:
winunixos wout;

and re-write your code:

wout << this << that << theother;

now you can implement operator<< to switch between platforms:

winunixos& operator<<(const char* string) {
#ifdef WIN32
windows code
#else
cout << string;
#endif
}

This sounds (to me) the correct OO abstraction, after all you want to
output to a multiplatform stream, not cout.

John McAleely
--
And you think these opinions are mine? Let alone anyone elses...
Remove the --- from my address to e-mail me. Sorry.

David W. Coppit <dw...@mamba.cs.virginia.edu> wrote in article
<5hqs74$i...@netlab.cs.rpi.edu>...


>
> I'm working with some code that I'm compiling for Windows and Unix. In
> Unix, simply saying "cout << ..." works great, but in Windows I have to
> append the string to a class variable, update the variable, redraw the

> screen, etc. One thing I could do is to #ifdef two implementations at
<snip: operator<< on win32 & unix>

Dietmar Kuehl

unread,
Apr 4, 1997, 3:00:00 AM4/4/97
to

Hi,
James Kanze (james-alb...@vx.cit.alcatel.fr) wrote:
: ku...@horn.informatik.uni-konstanz.de (Dietmar Kuehl) writes:

: |> David W. Coppit (dw...@mamba.cs.virginia.edu) wrote:
: |>

: |> : I'm working with some code that I'm compiling for Windows and


Unix. In
: |> : Unix, simply saying "cout << ..." works great, but in Windows I
have to
: |> : append the string to a class variable, update the variable,
redraw the
: |> : screen, etc.

: |>
: |> Although I know it is not covered in the C++ FAQ file, I think


this
: |> question is a FAQ... Here is the answer:
: |>
: |> The classes 'istream' and 'ostream' (aka 'basic_istream' and
: |> 'basic_ostream') are merely convenient frontends to an actual
: |> abstraction from the external representation.

: IMHO, slightly more than nits...

: The classes istream and ostream are more than just "convenient
: frontends"; they encapsulate an important abstraction (that of
formatted
: text) in their own right. In a very real sense, it is they that
: encapsulate the abstraction of an "external representation", not the
: streambuf class. (The abstraction encapsulated in the streambuf class
: and its derivatives is that of a data sink and source.)

I can agree with this view. I think what made me say that 'ostream' and
'istream' are just convenient frontends was the fact, that the actual
formatting is done by some facets ('num_put', 'num_get',...) of the
used 'locale' (at least in a standard conforming C++ library). The
stream classes become the binder between the different services of
'streambuf's and facets, containing the necessary formatting
information. Also, the convenient interface declares by itself a
certain abstraction...

: One thing that is common to the abstractions of both streambuf and


: [io]stream is the concept of a stream; both deal with linear streams
of
: data: one dimensional sequences. As such, they are not a particularly
: appropriate abstraction for a window, which is two dimensional and has
: direct access.

IMO it makes still sense to interpret [linear] sequences of textual
information in a window as "linear stream" and hence access it using
the stream abstraction: A 'windowbuf' can have members 'goto()' (and
whatever else is necessary like 'color()', 'font()' and 'angle()')
which setup a mode for the interpretation of the operations to come:
Where in the window the text has to be displayed or scanned, in what
color and font it has to be display etc. Writing text to a window using
the streams abstraction is a reasonable thing.

Reading text from a window is somewhat more complex, resulting from the
fact that a window is more like a form than a sequence: The user may
fill in fields in an arbitrary order rather than in a sequence. But
even here it may be reasonable to scan the text using the streams
abstraction: The entry fields can make up together a text sequence
which is scanned or maybe the text has to be entered linewise like in
the shells in an xterm.

: >From a conceptual point of view, I find it normal, and even


preferable,
: that the functionality of generating the text stream to be displayed,
: and actually displaying it, are separated. In the first, the
: abstraction is a stream (of text characters); in the second, the
: resulting text string is treated as a single object. I would thus
: expect that building the string and displaying it involve different
: actions on different objects. (Typically, the string will be built
: using wostringstream or ostringstream; one of the overloaded display
: functions of the window object will probably take a "string" as the
: object to be displayed.)

Yes but reasonable synchronization of the string created and the
currently displayed text can only be done over the streams
abstraction: It should be possible to use the stream effectively
writing to a window everywhere another '[io]stream' can be used. There
is no reasonable way to enforce synchronization of the stream with the
window different from using a special 'streambuf' to write to the
window. Thus, I think that the best approach is to use the window
abstraction (which I assumed anyway) is used by a 'windowbuf' directly
to display the string. When it is displayed is then completely up to
the implementer of the 'windowbuf': The characters can be displayed on
receipt or if the stream is flushed, whatever is more appropriate.

: |> This abstraction uses the


: |> base class 'streambuf' (aka 'basic_streambuf') as interface. If
you
: |> need a new external representation, you just derive from
'streambuf' a
: |> class which overrides the relevent virtual functions. For output
these
: |> are normally 'sync()' and 'overflow()' plus, to increase
performance,
: |> 'xsputn()'.

: I'm skeptical of using the streambuf abstraction for managing a
window.
: On one hand, it seems too limiting; there are too many things you can
do
: with a window that have no place in the abstraction. On the other
hand,
: it seems to leave to many of the details exposed; do you have to flush
: to ensure that the data appear, or does this happen automatically at
: some particular point in time, or...

The 'streambuf' abstraction is necessary if you want to write to a
window in a stream like fashion. Managing text in a window is IMO
reasonable to be encapsulated with a 'streambuf'. Like I mentioned
above, special actions like positioning or font changes can easily be
added to the 'windowbuf' using additional members. The details
remaining exposed are eg. also exposed for a 'stringbuf' and the exact
choice depends clearly on the use: If the user has to see the text
immediately, writing the characters directly is the only choice. If the
window interface is slow and can handle longer strings more
efficiently, flushing is probably the way to go. Of course, hybrid
approaches are also possible (and necessary anyway to handle buffer
overflow).

: [example code deleted...]


: |> For a more complete example of a stream buffer writing to a GUI
window,
: |> more precisely to a Motif Text Widget, have a look at
: |> <http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream/>.

: I've not looked at the code, and I'm not that familiar with X-Windows
: programming either. But a Text Widget is not a window, as far as I
: know.

A Text Widget is an abstraction for a [sub-] window containing textual
information. The view I have taken in the sample implementation is a
sequence of text pasted into a window (in X11 windows are just areas on
the screen and they may be nested into each other; I don't think that
the exact definition of "window" should be discussed here...). The
Widget (which are an object oriented approach to dealing with different
kinds of windows implemented in C) provides the necessary methods to
manipulated the text being displayed. The stream I have implemented
takes a very simple approach and appends everything written to it to
the end of the text. This is reasonable for example to provide windows
where you can sent log messages to or which are just used to display
some text. I agree that for more complex interactions, like editing, a
different mechanism may be more appropriate.

: The problem is that when outputting to a file and when outputting to a


: window, you are not outputting the same information. Outputting to a
: window requires MORE information (where, etc.).

That depends: If you want to write either to a file or to a window, it
is likely that you want to use the same mechansim in both cases. In
these cases, I think it appropriate to use a 'windowbuf' which is
derived from a 'streambuf'. Also, the thread started with a request
where text is written to 'cout' under UNIX and to a window under some
other system: This is the problem I addressed. If writing to 'cout' is
conceptually the right thing, just displaying text in some GUI window
is probably also the right thing. Sure, for a full fledged text
displaying window a lot more is necessary. ... but this would also
require much more time to answer, much more conceptual work, and is
probably not even required!

: |> : What I would like to do is to *redefine* what happens when one


tries to
: |> : write to a stream, so that the output is sent to a window.
Unfortunately,
: |> : when I try to do something like
: |>
: |> : ostream& operator << (const char* string) {
: |> : window->output_var = string;
: |> : window->UpdateData(FALSE);
: |> : window->Invalidate();
: |> : window->UpdateWindow();
: |>
: |> : return os;
: |> : }
: |>
: |> While this is reasonably easy to do for 'char const *' it is
already
: |> more complex eg. for a 'double' and is practically impossible to
do for
: |> a user defined type. Using the approach which is intended for this
: |> situation, namely derivation from 'streambuf', is less complex and
: |> works...

: Except that you somehow have to define *when* you do the update; every
: character, or only on explicit flush, or... (And this is neglecting
the
: problems of "where", "what color and font", etc.)

Writing to a window with (static)textual information is easy, even if
you want to provide for text positioning, different colors and font,
different writing angles, flashing, etc. (as long as the abstraction
for the text window can do such things): You can just use a 'windowbuf'
to do the formatting and manipulators or members to do the rest. What
is really problematic (at least to me; I would be interested if someone
has a good solution to this) is just reading from a window where the
user can enter at arbitrary positions.

The problem of when you update is not that bad, I think: Clearly, you
update the window if it is flushed. Depending on the run-time
characteristics of the application and the difference of single
characters being display and strings being displayed you would display
what you get or only when the stream is synchronized. I don't think
that there is much conceptual work to be done here: The exact timing
doesn't really matter that bad for user interaction. I just has to be
made sure that the text is displayed when a response from the user is
expected. But in this case the stream should be flushed anyway...

: IMHO, this approach (deriving from streambuf) is only appropriate for


: windows which, once created, act like streams. (A window which simply
: inserts output text at the end, as lines, and scrolls up as necessary,
: might be an example.)

... which is exactly what was required at the beginning of the thread!
But I don't fully agree with this position: I think there are much more
situation where it is reasonable to use a class derived from a
'streambuf' to write to a window. Read, as I pointed out, is something
completely different, though...

Finally, I want to point out that deriving from 'streambuf' is close to
always more appropriate than trying to [only] derive from 'ostream'
(this, in short, simply doesn't work) and using some template mechanism
to mimick the behavior of 'ostream': The 'streambuf' approach is the
one which is intended to solve those problems...


--
<mailto:dietma...@uni-konstanz.de>
<http://www.informatik.uni-konstanz.de/~kuehl/>
I am a realistic optimist - that's why I appear to be slightly
pessimistic

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

James Kanze

unread,
Apr 7, 1997, 3:00:00 AM4/7/97
to

ku...@horn.informatik.uni-konstanz.de (Dietmar Kuehl) writes:

First, the point of my previous posting wasn't to depreciate the work
Dietmar has done in creating a windowbuf, but simply to point out that
there were larger design issues to be considered. I've cut all but the
end of his posting; it contained a number of techical points about which
there is nothing more to say.

|> : IMHO, this approach (deriving from streambuf) is only appropriate for
|> : windows which, once created, act like streams. (A window which simply
|> : inserts output text at the end, as lines, and scrolls up as necessary,
|> : might be an example.)
|>
|> ... which is exactly what was required at the beginning of the thread!

I'm not sure. The original poster was concerned about general output;
it was not at all evident that he understood the different paradigms
involved. For example, a lot of programs use cout to output prompts for
input; from the parts of your posting that I've cut, I'm sure you agree
that just plugging in a windowbuf instead of the usual filebuf isn't
sufficient to make such a program run under Windows.

|> But I don't fully agree with this position: I think there are much more
|> situation where it is reasonable to use a class derived from a
|> 'streambuf' to write to a window. Read, as I pointed out, is something
|> completely different, though...

Yes. I was basically taking a fairly extreme view in order to stimulate
thought. While I don't really think that a streambuf derived class is
appropriate to manage a window (with borders, scrollbar's, etc.), it is
probably appropriate for display text in an existing window more often
than my posting would have led one to think (but still not always).

It's also worth pointing out that given the ubiquity of streambuf's,
it's sometimes worth forcing the application to fit, if the forcing
isn't too much, so as to remain in the domain of standard idioms.

|> Finally, I want to point out that deriving from 'streambuf' is close to
|> always more appropriate than trying to [only] derive from 'ostream'
|> (this, in short, simply doesn't work) and using some template mechanism
|> to mimick the behavior of 'ostream': The 'streambuf' approach is the
|> one which is intended to solve those problems...

Agreed. This is the most important point.

--
James Kanze home: ka...@gabi-soft.fr +33 (0)1 39 55 85 62
office: ka...@vx.cit.alcatel.fr +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
-- Conseils en informatique industrielle --

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Steve Willer

unread,
Apr 9, 1997, 3:00:00 AM4/9/97
to

James Kanze <james-alb...@vx.cit.alcatel.fr> wrote:

>The problem is that when outputting to a file and when outputting to a
>window, you are not outputting the same information. Outputting to a
>window requires MORE information (where, etc.).

>Except that you somehow have to define *when* you do the update; every


>character, or only on explicit flush, or... (And this is neglecting the
>problems of "where", "what color and font", etc.)

The question of "where" can be answered by constructor arguments. The
question of "when" can be dealt with by the destructor. At least, this
is how I have tackled this kind of problem. An example might be:

TextWidgetOutput(myWidgetHandle) << "Hi there, " << yourName;

TextWidgetOutput is a *class*, not an object. You're creating a
temporary here, and when the temporary goes away at the end of the
statement it takes the buffer it's built up and throws it into the
widget (or window or whatever).

I've been using this idiom quite often lately; I used it to tackle the
problem that we discussed a while ago -- language-independent output and
how to deal with arguments being in different positions and orders. An
example, using my "Local" class:

Local("Hi there, $! My name is $!") << yourName << myName;

A temporary Local is generated which converts the formatter string to a
local language (turning the dollar-signs into true positional arguments
$1$, $2$, etc. if necessary), then each argument is applied to it in
order. Local's destructor doesn't do anything, but it can be converted
into a string or "const char*" if you use a non-temporary. The real fun
is defining a bunch of subclasses that derive from Local and basically
just overload the destructor:

Tracelx -- outputs a trace at level "l"
Log -- outputs an error log entry
LCOut -- outputs to cout
LCErr -- outputs to cerr

Wonderful idiom.

>IMHO, this approach (deriving from streambuf) is only appropriate for
>windows which, once created, act like streams. (A window which simply
>inserts output text at the end, as lines, and scrolls up as necessary,
>might be an example.)

Not if you use the above approach.

0 new messages