Boost logo

Boost :

From: James Kanze (kanze_at_[hidden])
Date: 2002-02-16 11:20:35

Karl Nelson <kenelson_at_[hidden]> writes:

|> > "Rainer Deyke" <root_at_[hidden]> writes:

|> > |> > Okay, given the wide ranging discussion on formatting, I
|> > |> > have resubmitted my original format operator. (Thus placing
|> > |> > the code where my mouth is.)

|> > |> >

|> > |> > Feedback welcome!

|> > |> Overall, I like. Some comments:

|> > |> - The following should silently swallow the "foo" argument:

|> > |> cout << format("%2$s", "foo", "bar");

|> > |> Right now, it invokes undefined behavior.

|> > Why not an exception? (My own implementation treats the presence
|> > of a %2$ without a %1$ as an error.) Of course, he did say X/Open
|> > compatibility, and in X/Open printf, it is undefined behavior:-).

|> This is a very tough call. How would you know when a exception is
|> appropraite with a format operator? After all the strings are
|> coming in from outside source like gettext so if you throw
|> expections that means virtually every call to format would need to
|> be wrapped with try/catch. It is no fun having some
|> internationalization version of your code crash just because the
|> translator garbled some string, but then is silently displaying the
|> wrong text much better?

My thoughts exactly. My implementation aborts, but only because
exceptions weren't generally available when I wrote it. An exception in
this case allows you to continue, perhaps dropping the translation and
using the original text.

On another tangent: has anyone considered the possibility of wrapping
gettext with something that checks that the resulting format is
compatible with the given one. (In standard terms, this would mean
wrapping the std::messages::get function to ensure that the returned
string is compatible with the default.)

|> Currently it implements throw only if the format string is
|> uninterpretable. Theoretically, I could make it throw on conversion
|> to string when requested...

|> Ie.

|> try {
|> cout << format(gettext("%s %d"), name, count).throw_incomplete();
|> } catch (io::incomplete_error e) {
|> cerr << e.what() << endl;
|> }

|> That way it does not throw on incorrect number of arguments when the
|> user does not intend it.


This is a general problem. My own implementation distinguished three
states, initialization (with the initial parse of the format string),
insertion of the parameters, and the final conversion (conversion to
string or output to a stream). The number of parameters seen was
checked at the final conversion, and any attempt to pass a parameter
after the final conversion was a fatal error.

The obvious use of format is as a temporary, as we've seen in most of
the examples. But one could argue for other possibilities:

    format( "%s %d" ) fmt ;
    for ( int i = 0 ; i < 10 ; ++ i ) {
        cout << fmt.with( s[ i ] ).with( x[ i ] ) << '\n' ;

In this case, the conversion would cause the format object to revert to
the parameter insertion state. But that would forbid:

    format( "%s %d" ) fmt ;
    fmt.with( s ).with( i ) ;
    std::cout << fmt << '\n' ;
    logStream << fmt << '\n' ;

|> Second, what is reasonable here? Under Microsoft .Net they allow
|> the same argument to be used multiple times. Or an argument not to
|> be used. Should this be valid?

|> cout << format("%2$d %2$x", i, i);

|> It is not a problem to support this, the question is just would it
|> be useful?

That's definately useful. I do it occasionally myself.

James Kanze                                mailto:kanze_at_[hidden]
Conseils en informatique orientée objet/
                    Beratung in objektorientierter Datenverarbeitung
Ziegelhüttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)179 2607481

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