Boost logo

Boost :

From: Dave Abrahams (abrahams_at_[hidden])
Date: 2000-03-06 17:58:07

on 3/6/00 10:13 AM, Mark Borgerding at mborgerding_at_[hidden] wrote:

> dave abrahams <abraham-_at_[hidden]> wrote:
> original article:
>> I'm starting this thread to provoken discussion of potential improved
>> interfaces for formatted output (and possibly input). I hope this will
>> eventually result in a boost library.
>> Of course, most of the downsides of printf are well-known:
>> A. Not type-safe
>> B. Easy to crash it
>> C. Hard to extend (you need va_list, not-even-standard-yet
>> vsnprintf(), &c)
> The main reason I avoid printf statements is because of the lack of
> compile time checking. There can be some really unpleasant side effects.

<story _everyone_ has experienced at least once snipped>

>> boost::format( "%1 chickens can be found in coop number %2")
>> % chicken_cnt % coop_num;
> This is safer than a printf, but could still be prone to an error with
> unintended formatting tags in the format string. It does not employ
> compile-time checking.

Sure it does. It employs compile-time _type_ checking. And unlike printf, it
is able to check the number of arguments used at runtime. I think this is a
good compromise.

>> std::cout << x, y, z;
> Well you can do
> std::cout << (x, y, z);
> But I don't think the results are what you would want. (It will
> evaluate the expressions in left-to-right order and return z.

I realize that. Actually, that's what I would expect. Parentheses induce
strong visual grouping when I look at them. Anyway, I wasn't seriously
proposing *exactly* that syntax. We'd have to do something more like

boost::print(std::cout) << x, y, z;

> I played around with overloading the comma operator. The results were
> pretty disasterous. Way, way too error prone. Throw a couple of
> parens into the mix and the behavior is completely different from what
> you intended. The worst part is the silence with which it compiles.
> In this respect, it is no better than printf.

I disagree. Printf silently compiles things which crash. As far as I can
tell, the parens do exactly what I would expect them to. BTW, comma
overloading is successfully used by the blitz++ numerics library; I don't
see why it should be feared.

> Here is the gist of an approach I came up with at my last job. The
> idea was to construct a temporary with a reference to some templated
> type. Various modifiers could be done on the temporary, each of which
> returned a reference to self. There is then an operator << that knows
> how to insert one of these formatting objects into an ostream. All the
> modifiers are applied to the ostream, the object is inserted and then
> all the modifiers are set back to their original state. A helper
> template function can optionally be used to create the correctly
> formatting_object specialization -- this just makes the usage a little
> easier.
> The usage is less verbose and less error prone than applying the
> modifieres directly to the ostream. It is also much safer than using
> printf.
> for (int i=0;i<offsets.size();++i)
> cout << "offsets[" << i << "] = "
> << format(offsets[i]).setf(cout.hex).fill('0').width(8)
> << endl;

My colleague and I talked today, and I think we are agreed that it is much
clearer what's going on if all field width and alignment specifications go
in the format string. That is, the format string should give a picture of
what the final output looks like. Imagine writing this:

cout << boost::format("offsets[%1] = %w8%2\n", i,
boost::hex(offsets[i]).fill(0) );

That syntax sits much better with me.


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