Boost logo

Boost :

From: Brey, Edward D (EdwardDBrey_at_[hidden])
Date: 2002-01-29 17:02:59

> From: Karl Nelson [mailto:kenelson_at_[hidden]]
> >
> This looks more like formating reuse. I don't see this a presistent.
> What is wrong with this?
> void myclass::print_numbers(ostream& os, format_expr& fmt) {
> for (int i = 0; i != end_; ++i)
> os << format(fmt, numbers_[i]);
> }
> void caller() {
> format_expr fmt("--%x--");
> the_instance.print_numbers(cout, fmt);
> }

Yes, this would work, also. I'm assuming that format_expr can be
initialized with a format string plus any number of manipulators. I don't
see what having a separate object buys you, though. Actually, where the
real synergy would lie is in applying the manipulators to the ostream, which
currently is possible. By introducing the format layer (regardless of the
existence of format_expr), we are really taking a step back. If formatting
were native to ostream, we could leverage the existing manipulator
persistence (or reuse, if you prefer).

> > > Consider if I allow persistent manipulators and just have a simple
> > > reorder stream.
> > >
> > > cout << format( fstr) % 16 % hex % 16;
> > > Okay so if fstr is "[1] = [2] base 16" thus we print
> > > "16 = 10 base 16". But if manipulators are persistent if
> > > someone attempts to reverse the order in some translation they
> > > write "[2] ???? 16 = [1]", this implies
> > > cout << hex<<16 " ???? 16 = " << 16;
> > > Thus we print "10 ???? 16 = 10". Ouch, not what we want.
> >
> > It depends on the persistence semantics that are in force.
> I wouldn't
> > recommend using the semantics you assume for this example.
> The manipulator
> > should apply to all subsequent arguments, regardless of
> their placeholder
> > position. Then the example would come out fine.
> Still a hard call. You would have to know that hex should
> be sticky and apply it to every stringstream after that point.

Specifying whether a manipulator should be sticky (I've been using
persistent (vs. local)) should be syntactically simple, for example
"format("[1]")(sticky)[manip(local, param1)]", possibly with some of the
more common manipulators redone so that
"format("[1]")(sticky)[local(param1)]" is possible. It's up the programmer
to define his own scope for the manipulator: it's just a matter of how he
manages the lifetime of the format object.

> Isn't placing something into a stream automatically a method of char
> conversion? All that the type specifiers do is govern how
> the conversion
> is done. Unfortunately, to do a "good" job of defining a universal
> format string is strictly limited to what you can do with ostream and
> and what you can do with the post conversion string.

There is a type->string conversion, yes. I was saying that there shouldn't
be a type1->type2->string conversion, which I thought was your point also.
I agree that any specifiers in the placeholder just specify details of the
type->string conversion.

> > However, it doesn't make sense to gratuitously include
> such. The problem is
> > that if there is a mismatch, as you are proposing char and
> %d would be,
> > format has to do something about it. It can throw or
> silently fail, where
> > "silently fail" means display in the default rendering for
> that type. Each
> > option is wrong in some cases. Why make the code author
> respecify the type
> > that the compiler already knows perfectly well?
> It doesn't know how the user wants it printed. What base,
> what precision,
> should it be scientific or fixed?

Not exactly. Short of instructions from the user to the contrary, format is
free to assume that the user wants whatever is specified by the current
manipulator context. The context is the result of hard-coded defaults
overridden by persistent manipulators overridden by local manipulators. The
placeholder only needs a format specifier if the user wants to add one last

Boost list run by bdawes at, gregod at, cpdaniel at, john at