J
James Kanze
That's a fine answer. But not the end-all. I can think of many times
where the format is very context-specific. Where sometimes hex is 2
hexits, 4 hexits, 8 hexits, etc. But Your answer could work here too.
Exactly. For something rather general, like HexFmt, I'd
probably leave the first parameter, which specifies the number
of digits. But I wouldn't necessarily leave the second, which
in HexFmt allows adding any flags you might want.
Where do you reset the stream's settings? Or do they get left
in "whatever was last" state?
I reset them in the destructor. Since the object is always a
temporary, it gets destructed at the end of the full expression.
but it really doesn't take long to master 90% of the useful
features of it. Don't make it sound harder than it is.
Experience has shown me that most C programmers, even
experienced ones, only know about 10% of it.
It works well for debugging output, where you're not too
concerned with the format: almost everyone does retain that %d
outputs integers, %x does the same but in hex, and %f is for
fixed point. Most programmers quickly assimulate the x.y for
width and precision. Almost no one knows much about the
flags---note that one of the respondants here wondered why you
used octal in "%#08x" (Which, of course, isn't octal. The 0 is a
flag, and not part of the numeric value. Which can't be octal:
even in "%20.010f", the precision is 10, and not 8.)
Again, I'd never advocate printf() proper, when typesafe
alternatives are available. And boost::format DOES work with
user defined types.
Yes. Under the hood, boost::format uses ostream. *All* it
does, in fact, is set formatting flags. (I had a discussion
with the author in one of the forums at one point. I believe
that one of his goals was that formatting specifiers would only
affect the flags. In my case, in Gabi::Format (or GB_Format, as
it was back then---this was long before namespaces, or even
templates), someone challenged me to attain 100% compatibility,
so I did. Which meant intercepting some of the types (integral,
floating point, etc.) and doing some extra formatting by hand; I
then extracted this logic so that it would be easy to provide it
for user defined numeric types.
Quite frankly, the author of boost::format made the right
decision here. Well over half of my code was there to handle
special cases involving flags which 99% of the programmers have
never heard of. (On the other hand, the use of the % operator
for streaming is a disaster with regards to program
readability.)
Also, you're mentioned specifically in the boost::format docs,
which I did not realize until yesterday
I guess we'll just agree to do things differently. I am very
comfortable with printf() style formatters, and can read them
almost as quickly as plain code.
I'm very comfortable with them as well, having actually
implemented printf in the past, but most of my collegues aren't.
And of course, it still means specifying physical formatting
directly at the site of the output, which is a maintenance
nightmare.
I know how to use them when I need them, and they express the
vas majority of what I need to output. I find boost::format
to be a very useful tool when I need to do formatted IO very
simply.
When I have a custom type, I almost always add a
operator<<(ostream), and when appropriate I make it check the
flags on the stream for it's formatting. Thus, it works with
boost::format or ostream directly.
Lastly, I admit to being a C programmer still learning C++.
Iostreams do feel weird to me (I really liked Java's
to_string() model, iostreams is similar but inside out).
If it wasn't implicit, I'd go with the Java model as well.
Although both it and ostream have the disadvantage of cutting up
the output text into small bits and pieces, which causes
troubles for the translator. I've not looked at it lately, but
boost::format does support a simpler form of the format
specifier (i.e. "id = %1%, value = %2%"), and allows
manipulators, so you may be able to get the best of both worlds.
Provided they change the '%', of course. (I sort of like
something like:
Format( "%1%: %2%" ).with( id ).with( value )
But you'd not want a separate "with()" for the manipulators;
something like:
Format( "%1%: %2%" ).with( id, 3 ).with( HexFmt( 8 ), value ) ;
would be more like it.
Maybe I should go back and see what I can do with my old code,
incorporating ideas from Boost. (My code did allow specifying
width and precision in three different ways: as a constant in
the format specifier, like printf; as an additional "argument",
by specifying a "*" in the format specifier, again like printf;
or as a second or third argument to with() (if you were using
with(), instead of <<---my code supported both). Or just grab
the Boost code, and add support for with()---it seems to do
everything I want, except allow a readable format in the
expression using it.