Boost logo

Boost :

From: Terje Slettebø (tslettebo_at_[hidden])
Date: 2003-02-05 18:41:37


>From: "Jason House" <jhouse_at_[hidden]>

> Terje Slettebø wrote:
>
> > > It should handle maps and pairs
> > > reasonably well. I think that I have the same complaints about this
as
> > > io_manip
> > >
> > > The saving of information to the stream means that you can affect all
> > > future output...
> > >
> > > For instance, if you have a type
> > > map<custom_object, list<string> >
> > >
> > > and custom_object's stream output uses io_format<list<string> >, then
> > > you are going to run into trouble if it wants a different formatting.
> >
> > Right. That's a consequence of this. As you say too, I don't know any
> > obvious alternatives, though.
>
> I thought of one thing that might work reasonably well.
>
> How about making ++io_format< T > save the current format in a stack.
> and having io_format< T>-- restore the previously queuued format

I've thought of the exact same thing. :) Not how the syntax for it would be,
but when I was thinking of this, it suddenly occurred to me: State savers!

This essentially creates a scope in the state space. As you say, you may
then read the currently set format, and restore it afterwards. The
restoration is important, and there are issues such as exception safety.

> so, then something like
>
> > > std::cout << ++io_format<char (&)[3]>("\n|","|\n","|")--
> > > << ++io_format<char
(&)[3][3]>("-------","-------","-------")--
> > > << board << '\n';
>
> would save and restore the formating for char(&)[3][3] and char(&)[3] and
never
> stomp on anything else.

In this case, it seems it saves and restores the format, before the format
gets a chance to be used. In other words, the scope only covers the state
saving, not the output.

Another possibility might be to have a sentry object, doing automatic state
saving and restoring in the constructor and destructor. In fact, there are
already such classes in Boost: Daryle Walker's I/O state savers, which fits
this situation like a glove.

In your original posting, you had this example:

>For instance, if you have a type
>map<custom_object, list<string> >

>and custom_object's stream output uses io_format<list<string> >, then
>you are going to run into trouble if it wants a different formatting.

Such a custom object may then have something like the following in its
stream output:

boost::io::ios_pword_saver(stream,index);

// Set stream state, and do output.

That's all. :)

This also ensures that the state is restored properly, even in the presence
of exceptions, something the ++/-- way won't do. Of course, this requires
the pword-index, so one might make the interface more user friendly, and fit
the rest, for example by making the state saver a manipulator, itself.

As I understand, the lifetime of a temporary object extends until the end of
the full expression it's used in, so the following should be well-defined:

std::vector<int> v;

std::cout << composite_save<vector<int> >() << composite_format(...) << v <<
'\n';

This saves the format at the start, and restores it at the end.

An alternative is a named temporary, such as:

composite_save<vector<int> > sentry(stream);

// Set format and do output

> The net effect is that you can optionally add the extra few characters and
prevent
> stomping on other code that is displaying your class.

Exactly. :)

I feel fortunate to have so many competent people around me. This certainly
gives library building a boost. :)

Regards,

Terje


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk