Topic: Were positional parameters in iostreams considered for the Standard C++ Library?


Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/11/05
Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <38216a39.739086039@news.internetconnect.net>,
>   phalpern@newview.org (Pablo Halpern) wrote:
> > James.Kanze@dresdner-bank.com wrote:
> >
> > >In article <381a6b8a.346156917@news.internetconnect.net>,
> > >  phalpern@newview.org (Pablo Halpern) wrote:
>
> > >> How about the following:
>
> > >>   posstream mystrm("The temperature is %1 degrees %2");
> > >>   mystrm << pos(1) << dec << setw(2) << temp << pos(2) <<
> "Celsius";
> > >>   cout << mystrm.str();
>
> > >I considered something vaguely similar. Basically, however, I added
> > >an operator()( char const* ) to ostream, which returned an instance
> > >of my Format class, with operator<< instead of with.  There were
> > >several reasons I decided against it, but none of them killers:
>
> > >  - People are used to terminating with an "<< endl".  Whether this
> is a
> > >    good idea is discutable, but it is frequent, and any idiom using
> <<
> > >    should support it.  Which basically meant that I needed support
> for
> > >    inserting manipulators -- an added compilcation which I felt I
> > >    didn't need.
>
> > Using my approach, endl would simply insert a newline into the string
> > at whichever position was current. The user would quickly learn not to
> > use endl unless they mean it.
>
> The problem occurs when they do mean it.  Endl doesn't just insert a
> newline, it flushes the buffer.  (If all you want is a new line, use
> '\n'.)  How do you support manipulators which flush the buffer, or do
> other things like that?

The simplest approach would be to document that flushing inside an
argument has no effect.

A more complicated approach would be an "intelligent flushing"
approach, i.e. outputting all characters you already can determine
in the correct order:

// using my suggested syntax from other posting
cout << format("abc %1 def %3 ghi %2")
     << "aaaa" << flush << "bbbb" << endarg // "abc aaaa"
     << "cccc" << flush << "dddd" << endarg // "bbbb def "
     << "eeee" << flush << "ffff" << endfmt // "eeee"
     << flush;                              // "ffff ghi ccccdddd"

This would be more work, of course.

[...]

> > >  - Finally, it involved using a modification of ostream, rather than
> > >    the standard version.
>
> > I don't see why. I would derived posstream from ostream and
> > posstreambuf from streambuf (or basic_stream<> and
> > basic_streambuf<>). The hard work would be in posstreambuf.
>
> What does streambuf have to do with formatting?  And what does deriving
> from ostream buy you?  How does this interact with, say, ofstream, when
> the user wants to output to a file?

I can see one case where you'd want to override streambuf: If
you want to provide "intelligent flushing" in arguments. Since
the only place to catch all flushes is the streambuf, you'd be
forced to write your own just to catch flushes.

However, just making flush in arguments a no-op would IMHO be fine.

[...]


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/11/05
Raw View
phalpern@newview.org (Pablo Halpern) writes:
> But the methods in streambuf *are* virtual. Most of the work would be
> done there. There's no reason to override a non-virtual function of
> ostream.

Now I'm confused. The streambuf receives a stream of characters to
write from the ostream to which it belongs. How are you going to
sort out positional parameters from that?

> Note that operator << must either be a member template or else accept a
> const posstream& argument and cast-away const for the above to compile.

Sure. I write it as a member template.

> Also, while this seems like a reasonable short-hand, not all output is
> conveniently done in a single statement.

True enough. I don't have any experience in actually doing this sort
of i18n work, so I can't say whether this happens often or not.

> Using the destructor to flush the string to another stream would require
> a lot of user documentation and would support a very limited idiom,
> IMHO. Be wary of things that look slick for small examples, but don't
> scale well.

Well, I use the write-in-the-destructor approach in actual code at work
and it works just fine for me. It's actually in a case where using a new
streambuf would be the right thing to do, but we're using the old Sun C++
compiler, and I don't know how well that idiom is supported there.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/06
Raw View
Hyman Rosen <hymie@prolifics.com> wrote:

>phalpern@newview.org (Pablo Halpern) writes:
>> But the methods in streambuf *are* virtual. Most of the work would be
>> done there. There's no reason to override a non-virtual function of
>> ostream.
>
>Now I'm confused. The streambuf receives a stream of characters to
>write from the ostream to which it belongs. How are you going to
>sort out positional parameters from that?

The conversion from e.g. integer to a stream of characters is not
affected by the positional parameter code. The posstreambuf would
maintain an output string and an insertion position in that string. Any
stream of characters directed at the streambuf would be inserted into
the string. The pos() manipulator would call rdbuf() to get the
streambuf, then use dynamic_cast<posstreambuf*> to get the posstreambuf.
It can then change the insertion position. All other formatting
functions go through the normal ostream mechanism.

[...]
>Well, I use the write-in-the-destructor approach in actual code at work
>and it works just fine for me. It's actually in a case where using a new
>streambuf would be the right thing to do, but we're using the old Sun C++
>compiler, and I don't know how well that idiom is supported there.

My experience with older i/o libraries is that they are mostly
compatable with the standard, unless you need wide character streams.
The basic streambuf interface has been around a long time.

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/03
Raw View
"Richard Parkin" <rparkin@msicam.co.uk> wrote:

>Ron Natalie <ron@sensor.com> wrote in message
>news:381B25D9.224E702B@sensor.com...
>> Pablo Halpern wrote:
>>
>> >   posstream mystrm("The temperature is %1 degrees %2");
>> >   mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
>> >   cout << mystrm.str();
>> >
>
>After reading some of the ideas here about this sort of thing, I went off
>and wrote a class to do something very similar. The striking thing for me
>was how easy it was - I don't think I've missed anything serious, although
>there are improvements that I would like to consider.
>
>My approach was to have a class that had an internal stringstream, and a
>vector of strings for the parameters. A templated operator << just inserts
>into the stream, then calls a method to check to see if a real parameter had
>been inserted (this was so that that manipulators would work). If something
>had been inserted, the string was added to the vector of parameters, and the
>stringstream reset ready for the next one.
>The real work was done by an operator std::string, to parse the format
>string and replace the %1 etc with the appropriate parameters (a
>guess-the-eventual-length is used to stop memory thrashing when constructing
>the string).

I like the simplicity of your implementation. I would resist having an
operator std::string() and instead have an explicit str() function (a la
stringstream). Implicit conversions are something to be wary of and use
only if the syntactic sugar provides a real benefit.

>The main difference to the above was that
>a) no 'pos(1)' indicators are needed - if something is inserted that results
>in a string, then that is the next parameter.

Advantage: more compact.

Disadvantage 1: Each positional parameter must be represented by a
single, atomic, output operation. (e.g. if I want to output an integer,
X, surrounded by brackets, I would like to be able to say s << '[' << X
<< ']'; but I couldn't with your approach because the brackets and X
would be seen as three separate parameters.)

Disadvantage 2: More error prone. One think I hate about printf is the
number of bugs I find in printf code where either parameters are
reversed or a parameter is missing (the latter can cause a program to
crash). Forcing the use of pos(1), pos(2), etc. prevents these kinds of
errors. At what price compactness? (Of course, I'm somebody who puts
std:: in front of every use of a standard library feature, so you can
see that I'm not a compactness freak.)

>b) no type information is stored, as everything is formatted to a string
>immediately.
>
>An example:
>
>cout << Format( "Percentage of %2 : %1 %%" ) << setw(5) << percent <<
>"Things";

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/03
Raw View
Hyman Rosen <hymie@prolifics.com> wrote:

>
>phalpern@newview.org (Pablo Halpern) writes:
>> The thing I like about this approach is that manipulators work.
>
>You can get manipulators to work by using a single ostringstream
>in the posstream implementation.
>
>class posstream
>{

My approach would derive class posstream from ostream (or
basic_ostream<>) and thus manipulators would work for free. The main
code for my implementation would be in the posstreambuf class derived
from streambuf (or basic_streambuf<>).

IMO, it is imperitive that posstream be derived from ostream so that it
would work with existing stream-based code.

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/04
Raw View
James.Kanze@dresdner-bank.com wrote:

>In article <381a6b8a.346156917@news.internetconnect.net>,
>  phalpern@newview.org (Pablo Halpern) wrote:
>>
>> How about the following:
>>
>>   posstream mystrm("The temperature is %1 degrees %2");
>>   mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
>>   cout << mystrm.str();
>
>I considered something vaguely similar. Basically, however, I added an
>operator()( char const* ) to ostream, which returned an instance of my
>Format class, with operator<< instead of with.  There were several
>reasons I decided against it, but none of them killers:
>
>  - People are used to terminating with an "<< endl".  Whether this is a
>    good idea is discutable, but it is frequent, and any idiom using <<
>    should support it.  Which basically meant that I needed support for
>    inserting manipulators -- an added compilcation which I felt I
>    didn't need.

Using my approach, endl would simply insert a newline into the string at
whichever position was current. The user would quickly learn not to use
endl unless they mean it.

>  - I (and many others) prefer the printf style of format specifiers to
>    manipulators.  Somehow, "%6.2f" seems more natural than:
>        cout << fixed << setw( 6 ) << setprecision( 2 ) << ...

Wow! Shows what background you're from! I could never keep anything but
the most basic printf format specs in my head, especially when it comes
to left/right adjustment, field width, fill characters, etc. When I
first made the switch from printf to ostreams, I found the manipulator
syntax to be rather verbose, but as I've gotton used to it, I find
myself wondering "what is the big advantage of compactness?" Sometimes
manipulators are hard to remember, but the cheet-sheet is much shorter
than for printf. I also like the fact that you can create your own
manipulators for user-defined types (using xalloc). Never the less,
there are a lot of people who have used printf so long that it is
"natural" to them.

>  - Finally, it involved using a modification of ostream, rather than
>    the standard version.

I don't see why. I would derived posstream from ostream and posstreambuf
from streambuf (or basic_stream<> and basic_streambuf<>). The hard work
would be in posstreambuf.

>> The thing I like about this approach is that manipulators work.
>
>Beauty is in the eye of the beholder.  The thing I like about my
>approach is that you don't use manipulators:-).

The more I think about it, the more I think it may be desirable to
combine these approaches. Positional parameters useful for
internationalization. Sometimes, the format of the parameter should be
specified in the internationalized format string; in other cases, it
should be specified in the code (e.g. with manipulators). How would your
approach work with user-defined types (e.g. date and time classes)?

>> Also,
>> a positional parameter need not be a single expression. Everything
>> from one pos manipulator until the next pos manipulator would be
>> inserted at the specified insertion point. In fact, you can go
>> back-and-forth, first inserting some contents at position %1, then at
>> %2, then inserting more stuff at %1 (after the previously-inserted
>> stuff), etc. This would not be difficult to implement, I believe.
>
>I don't think I'd allow things out of order: the confusion is too
>great. And where does the data go before the first positional specifier?

It is certainly possible to prohibit adding parameters out of order and
to prohibit adding parameters before the first positional manipulator. I
was just thinking out loud when I wrote the paragraph above. I tend to
agree that going out of order is a bad idea.

>Another thing to think about in the implementation: what happens when
>the number of positional specifiers and the number of positional
>parameters don't agree, or when there is a hole in the positional
>parameters. My code, initially written before exceptions, generates an
>exception failure, but this is a bit brutal for anything except a proof
>of concept.

The str() function of posstream could check to see if all of the
parameters have been filled in. If not, it could throw an exception,
return an empty string, return a string with special "<null>" markers in
the missing locations, and/or set the stream state to fail() or bad(). I
think a combination of inserting null markers and setting failbit would
be the easiest to debug.

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/11/04
Raw View
phalpern@newview.org (Pablo Halpern) writes:
> My approach would derive class posstream from ostream (or
> basic_ostream<>) and thus manipulators would work for free. The main
> code for my implementation would be in the posstreambuf class derived
> from streambuf (or basic_streambuf<>).

Most of the methods in ostream are not virtual, so you could quickly
run into trouble doing it this way.

> IMO, it is imperitive that posstream be derived from ostream so that it
> would work with existing stream-based code.

If you're working with positional parameters, it seems pretty unlikely
to me that you would be doing so in a context of existing stream-based
code.

Despite the similarity of using operator<< on a posstream, what you
really have here is a way of accumulating arguments and spitting out
a result string at the end. I like writing my version to get a real
ostream as a constructor argument and letting the destructor write
the result to that stream.

 posstream("Name: %2, %1", cerr) << "John" << "Smith";
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Richard Parkin" <rparkin@msicam.co.uk>
Date: 1999/11/04
Raw View
Pablo Halpern <phalpern@newview.org> wrote in message
news:38226e94.740201122@news.internetconnect.net...
>

<snip details of my approach>

>
> I like the simplicity of your implementation. I would resist having an
> operator std::string() and instead have an explicit str() function (a la
> stringstream). Implicit conversions are something to be wary of and use
> only if the syntactic sugar provides a real benefit.

This is my worry too - implicit casts have a habit of being called just when
you least expect them.

The benefit though is the difference between:
std::string myString = Format( "%1 %2" ) << "one" << "two";
and
std::string myString = (Format( "%1 %2" ) << "one" << "two").str() ;
which is a bit clunkier. (See bottom of this message for the design forces
which led me to reject this)


> >The main difference to the above was that
> >a) no 'pos(1)' indicators are needed - if something is inserted that
results
> >in a string, then that is the next parameter.
>
> Advantage: more compact.
>
> Disadvantage 1: Each positional parameter must be represented by a
> single, atomic, output operation. (e.g. if I want to output an integer,
> X, surrounded by brackets, I would like to be able to say s << '[' << X
> << ']'; but I couldn't with your approach because the brackets and X
> would be seen as three separate parameters.)

I saw this too, but I rejected the argument because: it made implementation
simpler; it made certain programmer errors (forget a pos parameter?) less
likely; and most importantly, this situation is the uncommon case and there
is a simple work around:

std::string myString = Format( "%1 %2" ) << ( Format( "[%1]") << X  ) <<
"two";

> Disadvantage 2: More error prone. One think I hate about printf is the
> number of bugs I find in printf code where either parameters are
> reversed or a parameter is missing (the latter can cause a program to
> crash). Forcing the use of pos(1), pos(2), etc. prevents these kinds of
> errors.

But can cause other errors if they are missed too. It's a trade off - I came
down to no new 'special' manipulators to learn. Also it seemed redundant to
me to specify two orders (in the format string and in the insertion).

A third way - use endl to flush buffer as a parmeter and use the order of
insertion.

> At what price compactness? (Of course, I'm somebody who puts
> std:: in front of every use of a standard library feature, so you can
> see that I'm not a compactness freak.)

I agree - clarity and avoiding errors above
compactness-for-compactness-sake.

My solution was heaviliy influenced by a particular need - I needed to be
able to format a complex string as a parameter in situ (ie no local
variables, temporaries only)
ie DoStuff( Format( "...") << ..... );
and be a simple to use. This was because I was writing an error-checking and
exception reporting helpers for our programmers (most of whom are scientists
first, and programmers second). This was to reduce the amount of
housekeeping they had to contend with and let them get on with writing their
real code.

ie Check( expression, exceptionToThrow );

One force was that exceptionToThrow had to have *zero* overhead if the
expression is ok. This was achieved by doing sneaky expression
shortcircuiting in the Check macro (sorry - I was unable to use anything
else). But complex error message construction was needed in-situ, in as
'natural' a way as possible in this circumstance.

But we are digressing. This thread was about whether something like this
should have been put in the *standard*.

I think something could have been managed - some sort of intermediate stream
that buffered before flushing to an output stream. Ideally with no new
manipulators just for the formatter.

I'd still have to write a simpler-to-use helper around this, but the hard
work would have been done.

Ric
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/11/04
Raw View
In article <38216a39.739086039@news.internetconnect.net>,
  phalpern@newview.org (Pablo Halpern) wrote:
> James.Kanze@dresdner-bank.com wrote:
>
> >In article <381a6b8a.346156917@news.internetconnect.net>,
> >  phalpern@newview.org (Pablo Halpern) wrote:

> >> How about the following:

> >>   posstream mystrm("The temperature is %1 degrees %2");
> >>   mystrm << pos(1) << dec << setw(2) << temp << pos(2) <<
"Celsius";
> >>   cout << mystrm.str();

> >I considered something vaguely similar. Basically, however, I added
> >an operator()( char const* ) to ostream, which returned an instance
> >of my Format class, with operator<< instead of with.  There were
> >several reasons I decided against it, but none of them killers:

> >  - People are used to terminating with an "<< endl".  Whether this
is a
> >    good idea is discutable, but it is frequent, and any idiom using
<<
> >    should support it.  Which basically meant that I needed support
for
> >    inserting manipulators -- an added compilcation which I felt I
> >    didn't need.

> Using my approach, endl would simply insert a newline into the string
> at whichever position was current. The user would quickly learn not to
> use endl unless they mean it.

The problem occurs when they do mean it.  Endl doesn't just insert a
newline, it flushes the buffer.  (If all you want is a new line, use
'\n'.)  How do you support manipulators which flush the buffer, or do
other things like that?

> >  - I (and many others) prefer the printf style of format specifiers
to
> >    manipulators.  Somehow, "%6.2f" seems more natural than:
> >        cout << fixed << setw( 6 ) << setprecision( 2 ) << ...

> Wow! Shows what background you're from! I could never keep anything
> but the most basic printf format specs in my head, especially when it
> comes to left/right adjustment, field width, fill characters,
> etc. When I first made the switch from printf to ostreams, I found the
> manipulator syntax to be rather verbose, but as I've gotton used to
> it, I find myself wondering "what is the big advantage of
> compactness?" Sometimes manipulators are hard to remember, but the
> cheet-sheet is much shorter than for printf. I also like the fact that
> you can create your own manipulators for user-defined types (using
> xalloc). Never the less, there are a lot of people who have used
> printf so long that it is "natural" to them.

And Fortran specifiers before that: %6.2f is the same as F6.2 in a
Fortran specifier:-).

I implemented the whole works out of a sentiment of completeness.  In
practice, I agree with you for the lesser used features, but I suspect
that anyone who does scientific processing knows the difference between
the effects of %f and %e, for example.

The user defined manipulators are, of course, a problem.  My experience
are that they are little used, however.  To begin with, they make the
process of saving and restoring the formatting context significantly
more difficult.

I did provide for the possibility of customizing the inserters in my
format, with access to the complete format specifier in the
customization.  Users of this feature can extend formatting in any way
they like (recognize new modifiers, etc.).

> >  - Finally, it involved using a modification of ostream, rather than
> >    the standard version.

> I don't see why. I would derived posstream from ostream and
> posstreambuf from streambuf (or basic_stream<> and
> basic_streambuf<>). The hard work would be in posstreambuf.

What does streambuf have to do with formatting?  And what does deriving
from ostream buy you?  How does this interact with, say, ofstream, when
the user wants to output to a file?

> >> The thing I like about this approach is that manipulators work.

> >Beauty is in the eye of the beholder.  The thing I like about my
> >approach is that you don't use manipulators:-).

> The more I think about it, the more I think it may be desirable to
> combine these approaches. Positional parameters useful for
> internationalization. Sometimes, the format of the parameter should be
> specified in the internationalized format string; in other cases, it
> should be specified in the code (e.g. with manipulators). How would
> your approach work with user-defined types (e.g. date and time
> classes)?

It depends on whether there is a specialization for the templated
insertion function.  Without a specialization, the format specifier is
parsed, and used to set the various formatting flags and options on a
temporary ostream; the type is then output using operator<< to this
stream, which recovers the characters for the format.

If the insertion function is specialized, then of course, what actually
happens depends on the specialization.  The user has four or five
functions to work with:

getStream(): returns a stream with the flags and options set, as in the
    default implementation.

getRawStream(): returns a stream in the default state.

getModifiers(): returns the modifier field of the format specifier --
    basically, any non-alphanumeric characters or '0' which immediately
    follow the % -- as a string.

getWidth(), getPrecision(): you can guess.

getSpecifier(): returns the single alpha character which terminates the
    format specifier.  (I experimented with also allowing an extended
    specifier, in the form of <...>, where any text except '>' could
    appear between the < and the >.  I never actually found a use for
    it, though.)

> >> Also, a positional parameter need not be a single
> >> expression. Everything from one pos manipulator until the next pos
> >> manipulator would be inserted at the specified insertion point. In
> >> fact, you can go back-and-forth, first inserting some contents at
> >> position %1, then at %2, then inserting more stuff at %1 (after the
> >> previously-inserted stuff), etc. This would not be difficult to
> >> implement, I believe.

> >I don't think I'd allow things out of order: the confusion is too
> >great. And where does the data go before the first positional
> >specifier?

> It is certainly possible to prohibit adding parameters out of order
> and to prohibit adding parameters before the first positional
> manipulator.

> was just thinking out loud when I wrote the paragraph above. I tend to
> agree that going out of order is a bad idea.

> >Another thing to think about in the implementation: what happens when
> >the number of positional specifiers and the number of positional
> >parameters don't agree, or when there is a hole in the positional
> >parameters. My code, initially written before exceptions, generates
> >an exception failure, but this is a bit brutal for anything except a
> >proof of concept.

> The str() function of posstream could check to see if all of the
> parameters have been filled in. If not, it could throw an exception,
> return an empty string, return a string with special "<null>" markers
> in the missing locations, and/or set the stream state to fail() or
> bad(). I think a combination of inserting null markers and setting
> failbit would be the easiest to debug.

I rather tend toward setting failbit myself.  Except that my class also
supports conversion to string.  I'm not fully decided, but I think some
sort of exception is probably the best solution.

--
James Kanze                    mailto:James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/11/04
Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <381a6b8a.346156917@news.internetconnect.net>,
>   phalpern@newview.org (Pablo Halpern) wrote:
> > James.Kanze@dresdner-bank.com wrote:
> >
> > >I've done a lot of work in this domain myself.  My own solution is a
> > >Format class which allows writing something like:
> > >
> > >    cout << Format( gettext( <<An Open group printf format string>> )
> )
> > >            .with( param1 )
> > >            .with( param2 ) << '\n' ;
> > >
> >
> > How about the following:
> >
> >   posstream mystrm("The temperature is %1 degrees %2");
> >   mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
> >   cout << mystrm.str();
>
> > The posstream type would look somewhat like a stringstream except that
> > each insertion would be at a specific point within the string. This
> > cannot be simulated with a stringstream and seek operations because
> > inserting into the middle of stringstream *overwrites* rather than
> > *inserts* into the stream.
>
> I considered something vaguely similar. Basically, however, I added an
> operator()( char const* ) to ostream, which returned an instance of my
> Format class, with operator<< instead of with.  There were several
> reasons I decided against it, but none of them killers:
>
>   - People are used to terminating with an "<< endl".  Whether this is a
>     good idea is discutable, but it is frequent, and any idiom using <<
>     should support it.  Which basically meant that I needed support for
>     inserting manipulators -- an added compilcation which I felt I
>     didn't need.
>
>   - I (and many others) prefer the printf style of format specifiers to
>     manipulators.  Somehow, "%6.2f" seems more natural than:
>         cout << fixed << setw( 6 ) << setprecision( 2 ) << ...
>
>   - Finally, it involved using a modification of ostream, rather than
>     the standard version.
>
> > The thing I like about this approach is that manipulators work.
>
> Beauty is in the eye of the beholder.  The thing I like about my
> approach is that you don't use manipulators:-).

But you may have an overloaded operator<< that does already
use manipulators. So they will have to work anyway.

>
> > Also,
> > a positional parameter need not be a single expression. Everything
> > from one pos manipulator until the next pos manipulator would be
> > inserted at the specified insertion point. In fact, you can go
> > back-and-forth, first inserting some contents at position %1, then at
> > %2, then inserting more stuff at %1 (after the previously-inserted
> > stuff), etc. This would not be difficult to implement, I believe.
>
> I don't think I'd allow things out of order: the confusion is too
> great. And where does the data go before the first positional specifier?

Agreed. A nice syntax could be

cout << format("foo %2 bar %1 %3")
     << arg1 << endarg
     << arg2 << endarg
     << arg3 << endfmt;

To satisfy both the printf-style and the manipulator lovers,
the format string could contain format specifiers which are set
on the format manipulator for the first arg and on the endarg
for each following arg. Following manipulators would certainly
override that.

>
> Another thing to think about in the implementation: what happens when
> the number of positional specifiers and the number of positional
> parameters don't agree, or when there is a hole in the positional
> parameters. My code, initially written before exceptions, generates an
> exception failure, but this is a bit brutal for anything except a proof
> of concept.

With my syntax, you'd have several options:
- Missing args may be replaced by empty strings, or the final
  endfmt insertion may fail
- Additional args may be ignored, or insertion may fail.

If a failure results in an exception depends on the
exception flags, as usual.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/05
Raw View
Hyman Rosen <hymie@prolifics.com> wrote:

>phalpern@newview.org (Pablo Halpern) writes:
>> My approach would derive class posstream from ostream (or
>> basic_ostream<>) and thus manipulators would work for free. The main
>> code for my implementation would be in the posstreambuf class derived
>> from streambuf (or basic_streambuf<>).
>
>Most of the methods in ostream are not virtual, so you could quickly
>run into trouble doing it this way.

But the methods in streambuf *are* virtual. Most of the work would be
done there. There's no reason to override a non-virtual function of
ostream.

>> IMO, it is imperitive that posstream be derived from ostream so that it
>> would work with existing stream-based code.
>
>If you're working with positional parameters, it seems pretty unlikely
>to me that you would be doing so in a context of existing stream-based
>code.

In most cases that's true. However, because my version requires the
pos(1) manipulators, it is reasonable to pass the stream to otherwise
ignorant functions *between* positional manipulators. For example:

 exprtype e;
 posstream s("%1 is a complex expression equal to %2\n");
 s << pos(1);
 e.format(s, 2, 3); // Format expression to stream s
 s << pos(2) << e.eval();

>Despite the similarity of using operator<< on a posstream, what you
>really have here is a way of accumulating arguments and spitting out
>a result string at the end. I like writing my version to get a real
>ostream as a constructor argument and letting the destructor write
>the result to that stream.
>
> posstream("Name: %2, %1", cerr) << "John" << "Smith";

Note that operator << must either be a member template or else accept a
const posstream& argument and cast-away const for the above to compile.
Also, while this seems like a reasonable short-hand, not all output is
conveniently done in a single statement. E.g.:

 posstream s("The values are %1 and %2\n");
 s << pos(1) << expr1;
 s << pos(2);
 if (expr2 < 0)
   s << '(' << -expr2 << ')';
 else
   s << expr2;

Making the above into a single statement would produce rather obfuscated
code, if it can even be done. I prefer not to force the usage idiom.
Using the destructor to flush the string to another stream would require
a lot of user documentation and would support a very limited idiom,
IMHO. Be wary of things that look slick for small examples, but don't
scale well.
-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/05
Raw View
James.Kanze@dresdner-bank.com wrote:

>In article <38216a39.739086039@news.internetconnect.net>,
>  phalpern@newview.org (Pablo Halpern) wrote:
>> James.Kanze@dresdner-bank.com wrote:
>>
>> >In article <381a6b8a.346156917@news.internetconnect.net>,
>> >  phalpern@newview.org (Pablo Halpern) wrote:
>
>> >> How about the following:
>
>> >>   posstream mystrm("The temperature is %1 degrees %2");
>> >>   mystrm << pos(1) << dec << setw(2) << temp << pos(2) <<
>"Celsius";
>> >>   cout << mystrm.str();
>...
>
>> Using my approach, endl would simply insert a newline into the string
>> at whichever position was current. The user would quickly learn not to
>> use endl unless they mean it.
>
>The problem occurs when they do mean it.  Endl doesn't just insert a
>newline, it flushes the buffer.  (If all you want is a new line, use
>'\n'.)  How do you support manipulators which flush the buffer, or do
>other things like that?

Flushing the buffer doesn't do anything harmful. It might cause a slight
performance penalty, but since I'm formatting to a string, I'm not
really worried about that.

>...
>I did provide for the possibility of customizing the inserters in my
>format, with access to the complete format specifier in the
>customization.  Users of this feature can extend formatting in any way
>they like (recognize new modifiers, etc.).

Yes, but the programmer would need to learn a whole new mechanism,
rather than just use the manipulators he/she already wrote for
iostreams.

>> >  - Finally, it involved using a modification of ostream, rather than
>> >    the standard version.
>
>> I don't see why. I would derived posstream from ostream and
>> posstreambuf from streambuf (or basic_stream<> and
>> basic_streambuf<>). The hard work would be in posstreambuf.
>
>What does streambuf have to do with formatting?  And what does deriving
>from ostream buy you?  How does this interact with, say, ofstream, when
>the user wants to output to a file?

The real formatting is done by the vanilla ostream. The streambuf just
keeps track of the insertion point. The pos() manipulator would need to
be a bit sneaky and do a dynamic_cast<posstreambuf*> of the streambuf
before calling special positioning code in the posstreambuf.

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/11/05
Raw View
"Richard Parkin" <rparkin@msicam.co.uk> wrote:

>But we are digressing. This thread was about whether something like this
>should have been put in the *standard*.

Oh yeah, I forgot. Given the discussion in this thread, it seems to me
like this is best left as several non-standard libraries. There are
obviously several valid approaches serving different needs and tastes.
On the other hand, the lack of positional parameters does hamper
internationalization, so there might be a good argument for including
something in the standard.

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Richard Parkin" <rparkin@msicam.co.uk>
Date: 1999/11/02
Raw View
Ron Natalie <ron@sensor.com> wrote in message
news:381B25D9.224E702B@sensor.com...
> Pablo Halpern wrote:
>
> >   posstream mystrm("The temperature is %1 degrees %2");
> >   mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
> >   cout << mystrm.str();
> >
>
> Actually, this is sort of what my streamprintf class does.  When
> you apply it to a stream, it sucks up the args and then processes
> them with a hacked version of printf and the uses op<<(char) where
> the stdio printf would have done a putc.  The streamprintf op<<
> also squirrel away the data type (since printf has a much smaller
> range of valid types, you can pre overload << ops for all).

After reading some of the ideas here about this sort of thing, I went off
and wrote a class to do something very similar. The striking thing for me
was how easy it was - I don't think I've missed anything serious, although
there are improvements that I would like to consider.

My approach was to have a class that had an internal stringstream, and a
vector of strings for the parameters. A templated operator << just inserts
into the stream, then calls a method to check to see if a real parameter had
been inserted (this was so that that manipulators would work). If something
had been inserted, the string was added to the vector of parameters, and the
stringstream reset ready for the next one.
The real work was done by an operator std::string, to parse the format
string and replace the %1 etc with the appropriate parameters (a
guess-the-eventual-length is used to stop memory thrashing when constructing
the string).

The main difference to the above was that
a) no 'pos(1)' indicators are needed - if something is inserted that results
in a string, then that is the next parameter.
b) no type information is stored, as everything is formatted to a string
immediately.

An example:

cout << Format( "Percentage of %2 : %1 %%" ) << setw(5) << percent <<
"Things";

Ric
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Hyman Rosen <hymie@prolifics.com>
Date: 1999/11/02
Raw View
phalpern@newview.org (Pablo Halpern) writes:
> The thing I like about this approach is that manipulators work.

You can get manipulators to work by using a single ostringstream
in the posstream implementation.

class posstream
{
 ostringstream buf;
 ostream &out;
 string format;
 vector<string> args;
public:
 posstream(string f, ostream &o = cout) : format(f), out(o) { }
 template<typename T> posstream &operator<<(const T &item)
 {
  buf << item;
  args.push_back(buf.str());
  buf.str(string());
  return *this;
 }
 template<typename T> posstream &operator<<(ostream &(*man)(ostream &))
 {
  buf << man;
  if (buf.str().size() != 0)
  {
   args.push_back(buf.str());
   buf.str(string());
  }
  return *this;
 }
 ~posstream()
 {
  //... Process format for positional parameters, writing to out.
  //... Output-producing manipulators have their own position.
 }
};


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/11/03
Raw View
In article <381a6b8a.346156917@news.internetconnect.net>,
  phalpern@newview.org (Pablo Halpern) wrote:
> James.Kanze@dresdner-bank.com wrote:
>
> >I've done a lot of work in this domain myself.  My own solution is a
> >Format class which allows writing something like:
> >
> >    cout << Format( gettext( <<An Open group printf format string>> )
)
> >            .with( param1 )
> >            .with( param2 ) << '\n' ;
> >
>
> How about the following:
>
>   posstream mystrm("The temperature is %1 degrees %2");
>   mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
>   cout << mystrm.str();

> The posstream type would look somewhat like a stringstream except that
> each insertion would be at a specific point within the string. This
> cannot be simulated with a stringstream and seek operations because
> inserting into the middle of stringstream *overwrites* rather than
> *inserts* into the stream.

I considered something vaguely similar. Basically, however, I added an
operator()( char const* ) to ostream, which returned an instance of my
Format class, with operator<< instead of with.  There were several
reasons I decided against it, but none of them killers:

  - People are used to terminating with an "<< endl".  Whether this is a
    good idea is discutable, but it is frequent, and any idiom using <<
    should support it.  Which basically meant that I needed support for
    inserting manipulators -- an added compilcation which I felt I
    didn't need.

  - I (and many others) prefer the printf style of format specifiers to
    manipulators.  Somehow, "%6.2f" seems more natural than:
        cout << fixed << setw( 6 ) << setprecision( 2 ) << ...

  - Finally, it involved using a modification of ostream, rather than
    the standard version.

> The thing I like about this approach is that manipulators work.

Beauty is in the eye of the beholder.  The thing I like about my
approach is that you don't use manipulators:-).

> Also,
> a positional parameter need not be a single expression. Everything
> from one pos manipulator until the next pos manipulator would be
> inserted at the specified insertion point. In fact, you can go
> back-and-forth, first inserting some contents at position %1, then at
> %2, then inserting more stuff at %1 (after the previously-inserted
> stuff), etc. This would not be difficult to implement, I believe.

I don't think I'd allow things out of order: the confusion is too
great. And where does the data go before the first positional specifier?

Another thing to think about in the implementation: what happens when
the number of positional specifiers and the number of positional
parameters don't agree, or when there is a hole in the positional
parameters. My code, initially written before exceptions, generates an
exception failure, but this is a bit brutal for anything except a proof
of concept.

--
James Kanze                    mailto:James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: phalpern@newview.org (Pablo Halpern)
Date: 1999/10/30
Raw View
James.Kanze@dresdner-bank.com wrote:

>I've done a lot of work in this domain myself.  My own solution is a
>Format class which allows writing something like:
>
>    cout << Format( gettext( <<An Open group printf format string>> ) )
>            .with( param1 )
>            .with( param2 ) << '\n' ;
>

How about the following:

  posstream mystrm("The temperature is %1 degrees %2");
  mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
  cout << mystrm.str();

The posstream type would look somewhat like a stringstream except that
each insertion would be at a specific point within the string. This
cannot be simulated with a stringstream and seek operations because
inserting into the middle of stringstream *overwrites* rather than
*inserts* into the stream.

The thing I like about this approach is that manipulators work. Also, a
positional parameter need not be a single expression. Everything from
one pos manipulator until the next pos manipulator would be inserted at
the specified insertion point. In fact, you can go back-and-forth, first
inserting some contents at position %1, then at %2, then inserting more
stuff at %1 (after the previously-inserted stuff), etc. This would not
be difficult to implement, I believe.

Any feedback before I try to implement it?

-------------------------------------------------------------
Pablo Halpern                            phalpern@newview.org

I am self-employed. Therefore, my opinions *do* represent
those of my employer.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Ron Natalie <ron@sensor.com>
Date: 1999/10/31
Raw View
Pablo Halpern wrote:

>   posstream mystrm("The temperature is %1 degrees %2");
>   mystrm << pos(1) << dec << setw(2) << temp << pos(2) << "Celsius";
>   cout << mystrm.str();
>

Actually, this is sort of what my streamprintf class does.  When
you apply it to a stream, it sucks up the args and then processes
them with a hacked version of printf and the uses op<<(char) where
the stdio printf would have done a putc.  The streamprintf op<<
also squirrel away the data type (since printf has a much smaller
range of valid types, you can pre overload << ops for all).
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James.Kanze@dresdner-bank.com
Date: 1999/10/21
Raw View
In article <pPyO3.14480$0G2.535303@typ12.nn.bcandid.com>,
  "Matthew Blakley" <zarcher.nospam@yahoo.com> wrote:

    [...]
> I want to correct some misinformation I repeated from a recent tech
> lunch I attended: printf (the standard version) does not have
> positional parameters per se.

On the other hand, the printf on many, if not all Unix platforms has
been extended to support positional parameters, see
http://www.db.opengroup.org/sud, then follow on to printf.

> While it provides for templatized
> insertion and conversion, the order of the format specifiers is
> fixed. Whereas, if the string in the form manipulator were localized
> into another language with a different grammatical structure than
> english, the translator might return something such as "today, to the
> <2> went <1>".

Right.  Basically, standard printf and iostream are not usable in an
international environment.

> To address the overhead issue, I want to state that I've only started
> delving into the guts of the iostream framework and may misstate some
> points. Any corrections by more knowledgable persons would be
> appreciated.  From my understanding of iostreams, all the capabilities
> to provide positional parameters are already present for streams with
> seekable (or buffered seekable) output. As such, there would be no
> overhead involved in these manipulators unless they were actually
> used, and then only in the specific locations where they were used.

I've done a lot of work in this domain myself.  My own solution is a
Format class which allows writing something like:

    cout << Format( gettext( <<An Open group printf format string>> ) )
            .with( param1 )
            .with( param2 ) << '\n' ;

The class makes two passes over the format string, the first in the
constructor to pick up the formatting information for each parameter,
and the second when called on to output itself (or convert itself to a
string).

The class is implicitly expandable to any type which supports operator<<
to an ostream.  It uses the formatting parameters to set up a default
ostream.  The member function with is a template function.

The class also supports specialization of with for special cases (and in
fact provides specialization for the built-in types).  There are
functions to allow the specialized functions to access the original
formatting string -- the specializations on the integer types, for
example, use this to convert the parameter to a double and pass it to a
floating point version when the conversion specifier is d, e or f.

> Still, my original question to the group was if these were or are
> being considered for the standard. I mean no disrespect with this
> question, I think the standards committee has done an excellent job.

At present, the only thing being considered is corrections to actual
errors or ambiguities in the standard.

--
James Kanze                    mailto:James.Kanze@dresdner-bank.com
Conseils en informatique orient   e objet/
                  Beratung in objekt orientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(069)63198627


Sent via Deja.com http://www.deja.com/
Before you buy.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Matthew Blakley" <zarcher.nospam@yahoo.com>
Date: 1999/10/18
Raw View
The positional parameters can be anything that is insertable into a stream.
However, this does not diffuse compile time safety as the positional
parameters do not specify any pseudo-type information. The positional
manipulators only change the current insertion point in the stream. All
formatting and conversion would be done through the iostream framework. The
example I provided was meant to be simple and only used constant character
strings; however, any type and formatter should be insertable into each
position.

I want to correct some misinformation I repeated from a recent tech lunch I
attended: printf (the standard version) does not have positional parameters
per se. While it provides for templatized insertion and conversion, the
order of the format specifiers is fixed. Whereas, if the string in the form
manipulator were localized into another language with a different
grammatical structure than english, the translator might return something
such as "today, to the <2> went <1>".

To address the overhead issue, I want to state that I've only started
delving into the guts of the iostream framework and may misstate some
points. Any corrections by more knowledgable persons would be appreciated.
>From my understanding of iostreams, all the capabilities to provide
positional parameters are already present for streams with seekable (or
buffered seekable) output. As such, there would be no overhead involved in
these manipulators unless they were actually used, and then only in the
specific locations where they were used.

Still, my original question to the group was if these were or are being
considered for the standard. I mean no disrespect with this question, I
think the standards committee has done an excellent job.

Siemel B. Naran <sbnaran@uiuc.edu> wrote in message
news:slrn80k7br.tr3.sbnaran@localhost.localdomain...
>
> On 17 Oct 99 10:21:41 GMT, Matthew Blakley <zarcher@nospam.yahoo.com>
wrote:
>
> >    cout << form("<1> went to the <2> today.")
> >            << pos(1) << "Bob"
> >            << pos(2) << "store"
> >            << endf;
>
> >Is anything of this nature being considered for future revisions of the
> >standard?
>
> This will just make extra overhead, because operator<< may now do one
> of two things -- either write to the stream or fill in a positional
> parameter.
>
> What about type safety?  Must "<1>" be a string or int or what?  If
> it is always a string, then use
>    printf("%s went to the %s today." ,"Bob", "store")
> If "<1>" can be anything, then we are back to regular old printf
> with all its problems -- lack of compile time type safety, limited
> to only the fundamental types, no exception safety.
>
>
> Also consider writing your own manipulators
>
>    class Went {
>       public:
>          Went(char const * who, char const * where) : who(who),
where(where) { }
>          std::ostream& friend operator<<(std::ostream&, const Went&);
>       private:
>          char const *const who;
>          char const *const where;
>    };
>
>    std::ostream& operator<<(std::ostream& ostream, const Went& went) {
>       return ostream << went.who << " to the " << went.where " << "
today.";
>    }
>
> --
> --------------
> siemel b naran
> --------------
>
>
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]
>
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]