Boost logo

Boost :

From: Brey, Edward D (EdwardDBrey_at_[hidden])
Date: 2002-01-29 14:52:55


> From: Karl Nelson [mailto:kenelson_at_[hidden]]
>
> Why should their be persistent manipulators in a format stream.
> They don't make sense because they can get moved up when reordered.

Persistent manipulators allow for useful factorizations. If you are about
to output 5 numbers, and you want them all as hex, it is convenient to only
have to specify hex once.

Likewise, persistent manipulators help with generic code. For example:

void myclass::print_numbers(ostream& os, format& fmt) {
  for (int i = 0; i != end_; ++i)
    os << fmt[numbers_[i]];
}

void caller() {
  format fmt("--[1]--")(hex);
  the_instance.print_numbers(cout, fmt);
}

Of course, in this simple example, hex wouldn't have to be specified as a
manipulator, but you get the point. There is power in passing a pre-cooked
format object into an output function.

> 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.

> > Only the %d confuses the issue. I would expect the %d to
> be applied to each
> > argument, meaning for c=3 you would get: " Change is 433".
> This is a good
> > example of why is it best of avoid type specifiers unless
> you really want to
> > override the current format specified by the manipulator
> context (e.g.
> > override decimal with hex or vice verse).
>
> I take this argument a completely different way. Yes, type
> specifiers
> should not convert types, but rather they simply should not be taken
> as literial.
>
> I take the type as being very general.
> x - stream is hex (any numbers in it are shown as hex)
> d - stream is decimal (any numbers in it are shown as decimal)
> s - string literal (stream defaults)
>
> Thus %d on group(c>0?'+':'-',c) is "<< dec << '+' << 3".
>
> We don't try to convert the argument. It is also almost impossible
> to do because, we would have to force the types to fix basic types
> to interpret them.

I agree that format should not be in the business of type conversions.
"char" is ambiguous in terms of how it should be represented (kind of like
bool with "0" or "false"). I can see value in
manipulators/format-specifiers that allow specification of how char is to be
displayed.

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? In the case of templates,
the compiler knows it better than the author. I just don't see what value
there is in specifying a type in the placeholder. Changing the formatting
within the class of formats for a given type is fine. But just a type
specification with no (desired) effect, I don't understand.


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