From: Brendan on
On Apr 23, 12:14 pm, "Niels Dekker - no return address"
<nore...(a)this.is.invalid> wrote:
> Does the Standard Library support creating an std::string by means of
> streaming, without having to declare a *named* ostringstream object? I
tried
> the following:
>
> #include <sstream>
> #include <string>
> int i = 42;
>
> std::string s = (std::ostringstream() << "i = " << i).str();
>
> Of course it didn't compile, because a temporary (std::ostringstream())
cannot
> be passed as non-const reference to a function (operator<<). Okay, second
> try, wrapping the ostringstream as follows:
>
> template <typename T> class Wrapper {
> T m_data;
> public:
> T & get() {
> return m_data;
> }
> };
>
> std::string s = (Wrapper<std::ostringstream>().get() << "i = " <<
i).str();
>
> Unfortunately it still didn't compile, because operator<< returns an
> std::basic_ostream, instead of an std::ostringstream, and therefore it
doesn't
> have an str() member function. Now I wonder, is it safe to cast the
stream,
> returned by operator<< to an ostringstream reference? As follows:
>
> std::string s =
> static_cast<std::ostringstream&>(Wrapper<std::ostringstream>().get()
> << "i = " << i).str();
>
> At least, it *seems* to work... But is it the proper way to do it?

I actually like your workaround, although you should typedef
Wrapper<std::ostringstream> to make it cleaner. I believe that
temporaries are guaranteed to stick around until the next statement,
so you are good. Oh! also, overload << something like this:

std::string operator<<(basic_ostream& stream, ToStr& tstr) {
return static_cast<std::ostringstream&>(stream).str();
}

I haven't tested that, and obviously it isn't type safe, but since <<
is left associative you should be able to:

string x = temp_ostringstream().get() << "i = " << i << to_str;

where to_str is the single instance of ToStr.

Pretty nifty eh? There's probably some way to make getting the
temporary ostringstream easier, and maybe even making this statically
type safe, but it's late...

iostreams << are pretty lame for formatting syntactically speaking and
pretty much everybody ends up rolling their own formatting utility on
top of it.

Check out:

http://www.boost.org/doc/libs/1_35_0/libs/format/doc/format.html

which is basically a typesafe printf.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: guinness.tony on
On 2 May, 19:45, "Niels Dekker - no return address"
<nore...(a)this.is.invalid> wrote:
> Tony (aka "Guinness Tony") wrote:

<snip>

> > // partial specializationss
> > template<class traits>
> > basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
> ...
>
> > [how odd - I've never noticed that "specializationss" typo before!]
>
> Actually those overloaded operator<< functions aren't even template
> specializations! In 2001 it was already noticed by Andy Sawyer: LWG issue 311
> "Incorrect wording in basic_ostream class synopsis"http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#311

Indeed, but that resolution didn't seem to make it into the
2003 revised standard (from which I quoted the declarations.)

<snip>

> Interesting!!! That could be a source of very nasty bugs, especially when
> switching from one library implementation to another!

All library implementations should follow the standard and
thus behave in a consistent (if surprising) manner. Some
pre-standard libraries implemented the (char const*)
inserters as members, but surely we are talking about
standards-conformant implementations, here? Even the
still-all-too-popular MSVC++6's library implements them
as non-members (although the compiler silently permits
binding of temporaries to non-const references, so

int i = 42;
std::string s = static_cast<std::ostringstream&>(
std::ostringstream() << "i = " << i).str();

....actually works with that compiler, producing the
"expected" result, for all the wrong reasons!)

> Still, why do you think the "flush trick" is superior to creating a
> "temporary" lvalue by means of a wrapper?

Sorry - I didn't mean to claim superiority; I just
wanted to add an alternative solution to the mix.

> Do you have any references, showing
> that the "flush trick" is indeed a well-known idiom?

Well, I recall having first encountered it in a
discussion in one of the clc++/clc++m newsgroups,
presented by one of the regulars. After a bit of
searching, I've finally discovered that thread:

http://groups.google.co.uk/group/comp.lang.c++.moderated/browse_thread/thread/28f0226f8809eff5/

To my chagrin, I see now that Alf introduced it as
"a nasty trick" and James questioned whether it is
a "clean" solution. How my memory plays tricks!
"Idiomatic" is certainly not a description of
this technique and I retract my use of that term.
"A curiosity" is probably nearer the mark.

> (I wonder how many
> people actually /know/ that std::flush is inserted by a member function, while
> other objects, e.g., strings, are inserted by non-member functions.)

Alf's original presentation of this method actually
used the ostream::flush() member function (why didn't
I remember it that way?), so knowledge of how
std::flush() is inserted becomes moot.

> Otherwise I think I'll stick to the wrapper...

I think that's probably for the best!

Regards,
Tony.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]