Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to build a string on the fly, using std::ostringstream?

893 views
Skip to first unread message

Niels Dekker - no return address

unread,
Apr 23, 2008, 3:14:37 PM4/23/08
to
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?


Kind regards,
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center

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

Martin York

unread,
Apr 24, 2008, 3:05:54 AM4/24/08
to
On Apr 23, 12:14 pm, "Niels Dekker - no return address"

<nore...@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:

<DELETED>

>
> At least, it *seems* to work... But is it the proper way to do it?


Is your problem that you have other objects of non string types that
you want to append onto a string. In this case you could use
boost::lexical_cast()


std::string s = std::string("i =
").append( boost::lecical_cast<std::string>(i) );

--

Peter Jones

unread,
Apr 24, 2008, 3:10:33 AM4/24/08
to
"Niels Dekker - no return address" <nor...@this.is.invalid> writes:
> Does the Standard Library support creating an std::string by means of
> streaming, without having to declare a *named* ostringstream object?

What's wrong with:

,----
| #include <iostream>
| #include <sstream>
| #include <string>
|
| int main (int argc, char *argv[])
| {
| std::ostringstream os;
| int i = 42;
|
| os << "i=" << i;
| std::string s = os.str();
|
| std::cout << s << std::endl;
| }
`----

Are you just trying to make your code as terse as possible? Why would
you want to create a string from an ostringstream without having to
use a named ostringstream?

--
Peter Jones [pjones at domain below]
pmade inc. - http://pmade.com

Carl Barron

unread,
Apr 24, 2008, 3:43:21 AM4/24/08
to
In article <480ef5ff$0$14345$e4fe...@news.xs4all.nl>, Niels Dekker -

no return address <nor...@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>

void foo()
{


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


No but, most general and easiest solution is to put the ostringstream
in a block.

void foo()
{
int i= 42;
std::string s;

{
std::ostringstream oss;
oss << "i = " << i ;
s = oss.str();
}
}

this has the same effect as what your errant code is supposed to do.
and does not flood the code with temp variables that live longer than
needed. that is the ostringstream is destroyed on exit from the short
block.

--

Vidar Hasfjord

unread,
Apr 24, 2008, 5:12:53 PM4/24/08
to
On Apr 23, 8:14 pm, "Niels Dekker - no return address"

<nore...@this.is.invalid> wrote:
> 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<<).

Well, that is not the case on the implementations I use (VC7.1/VC9.0).
The << operator is implemented as a member of ostream; which does bind
to temporaries; so this works fine:

ostringstream () << "i = " << i; // compiles

I don't know if the standard mandates this or not though.

> 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.

Yes, the reason it doesn't work is type erasure. The first application
of << returns ostream&, and ostringstream::str can not be applied to
an ostream.

> Now I wonder, is it safe to cast the stream, returned by operator<< to an
> ostringstream reference?

Yes, you can recover the type in this way, but pedantically you should
use a dynamic_cast to do so.

dynamic_cast <ostringstream&> (ostringstream () << ...).str ();

This is ugly and verbose though. An alternative wrapper solution that
I use is based on forwarding the << operator call:

struct S { // string builder
std::ostringstream s;

template <typename T>
inline S& operator << (const T& v) {
using ::operator <<; // Note: Ugly disambiguation.
s << v;
return *this;
}
inline operator std::string () const
{return s.str ();}
};

Usage:

string s = S () << "i = " << i;

This works for me in practice. But you may stumble into problems
caused by less-than-perfect forwarding (e.g. ambiguities). I haven't
studied the best solution to this yet.

Regards,
Vidar Hasfjord

--

Brendan

unread,
Apr 24, 2008, 5:43:20 PM4/24/08
to
On Apr 23, 12:14 pm, "Niels Dekker - no return address"

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.

--

Brendan

unread,
Apr 25, 2008, 12:22:59 PM4/25/08
to
Here's a cleaned up version of the code I posted last night for inline
string formatting, which has been actually tested and works. The new
format is

STR_BEGIN << "asdf" << 123 << STR_END

and can be placed in a function like f(STR_BEGIN << "x = " << x <<
STR_END);

You might ask, how is this code type safe? Can't I write:
std::cout << "asdf" << STR_END;

No, you cannot. Give it a try. This is actually my biggest reservation
about this code, because I use an evil macro hack to ensure type
safty. Specifically, there are unbalanced parens in the macro. This
forces STR_BEGIN and STR_END to always appear as a pair, and allows
you to nest them and do things like

std::cout << STR_BEGIN << "asdf" << STR_END;

which would not work right if there were no parens there.

What do you think? Is this too much of a hack? Are there edge cases
I'm missing? Is there a better way?

-Brendan Miller

#include <iostream>
#include <sstream>
#include <string>

template <typename T> class Temporary {


T m_data;
public:
T & get() {
return m_data;
}
};

struct ToStr {
static ToStr instance;
};

ToStr ToStr::instance;

#define STR_BEGIN ((Temporary<std::ostringstream>().get())
#define STR_END (ToStr::instance))

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

void f(std::string str) {
std::cout << str;
}

int main(int argc, char** argv) {
// proper use.
f(STR_BEGIN << "asdf" << 123 << STR_END);

return 0;

Niels Dekker - no return address

unread,
Apr 26, 2008, 10:46:24 AM4/26/08
to
Thanks to all of you for your replies so far!

Martin York wrote:
> Is your problem that you have other objects of non string types that
> you want to append onto a string. In this case you could use
> boost::lexical_cast()

Yes, I would like to append any number of objects onto a string. And
you're right, I could indeed use boost::lexical_cast. But in my case, I
think it's too expensive and too verbose to do so:

std::string s = boost::lexical_cast<std::string>(obj1) +
boost::lexical_cast<std::string>(obj2) +
boost::lexical_cast<std::string>(obj3) +
boost::lexical_cast<std::string>(objN);

Peter Jones wrote:
> Why would you want to create a string from an ostringstream
> without having to use a named ostringstream?

Actually I was thinking of defining a macro, as follows:

#define STRING(arg) \
static_cast<std::ostringstream&>( \
Wrapper<std::ostringstream>().get() << arg).str()

It would allow doing:

std::string s1 = STRING("i = " << i);
std::string s2 = STRING(obj1 << obj2 << obj3 << objN);

Clearly such a macro definition would need an unnamed temporary to do
the streaming.

I wrote:
>> 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<<).

Vidar Hasfjord replied:


> Well, that is not the case on the implementations I use (VC7.1/VC9.0).
> The << operator is implemented as a member of ostream; which does bind
> to temporaries; so this works fine:
>
> ostringstream () << "i = " << i; // compiles

Oops, an oversight on my side! Both www.dinkumware.com/exam and
www.comeaucomputing.com/tryitout do indeed accept inserting a literal
string onto a temporary ostringstream. So apparently those
implementations have defined this particular operator<< as a member
function!

> I don't know if the standard mandates this or not though.

The Draft <www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2521.pdf>,
[ostream] specifies operator<< for C-style strings as a non-member:

template<class charT, class traits>
basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&,
const char*);

Interestingly, the Draft also provides a new set of overloads, having an
rvalue reference to an ostream as first argument. So C++0X would
certainly support inserting objects onto a temporary stream! :-) I
only wonder why the old "C++03" operator<< functions (having an lvalue
reference as stream argument) aren't removed from the Draft...

Vidar Hasfjord wrote:
> An alternative wrapper solution that I use is based on
> forwarding the << operator call:
>
> struct S { // string builder
> std::ostringstream s;
>
> template <typename T>
> inline S& operator << (const T& v) {
> using ::operator <<; // Note: Ugly disambiguation.
> s << v;
> return *this;
> }
> inline operator std::string () const
> {return s.str ();}
> };
>
> Usage:
> string s = S () << "i = " << i;

Cool!!! It looks much better than my approach!

> This works for me in practice. But you may stumble into problems
> caused by less-than-perfect forwarding (e.g. ambiguities).

Can you please explain? All I can think of is getting into troubles,
because of an operator<< overload that would have a non-const reference
as last argument. E.g., operator<<(ostream&, Foo &). But I guess
offering such an operator<< would be bad practice anyway. Don't you
think?

Brendan wrote:
> I actually like your workaround, although you should typedef

> Wrapper<std::ostringstream> to make it cleaner. [...]


> 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.

Thanks Brendan, that's a cool idea as well! (Especially if Vidar's
less-than-perfect forwarding get me into too much trouble...) Still
Vidar has another point: we should use dynamic_cast, while he doesn't
need to!

> Here's a cleaned up version of the code I posted last night for inline
> string formatting, which has been actually tested and works.

I'm glad you no longer pass ToStr by reference, in your cleaned up
version! So now you can remove your static ToStr::instance as well, and
pass a temporary ToStr():

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

BTW, instead of temp_ostringstream::get(), we could also add a member
function, temp_ostringstream::operator*(), to be used as follows:

string x = *temp_ostringstream() << "i = " << i << ToStr();

Looks even better, doesn't it?

> The new format is
> STR_BEGIN << "asdf" << 123 << STR_END

...


> #define STR_BEGIN ((Temporary<std::ostringstream>().get())
> #define STR_END (ToStr::instance))

...


> You might ask, how is this code type safe? Can't I write:
> std::cout << "asdf" << STR_END;
> No, you cannot.

Good point. The non-macro version would cause a runtime error
(std::bad_cast, if we're using dynamic_cast), instead:
std::cout << "asdf" << ToStr(); // runtime error

Your compile time error is surely preferable.

> What do you think? Is this too much of a hack? Are there edge cases
> I'm missing? Is there a better way?

Some people like macro hacks better than others... I guess it's a
matter of taste. It has to compete against my STRING macro, and Vidar's
string builder. I *think* that Vidar's less-than-perfect forwarding
issue can be fixed in C++0x (using std::forward), which would
*eventually* make his approach superior... Don't you think?

Kind regards,

Niels

Carl Barron

unread,
Apr 27, 2008, 9:13:20 AM4/27/08
to
In article <481317A5...@this.is.invalid>, Niels Dekker - no
return address <nor...@this.is.invalid> wrote:

>
> Some people like macro hacks better than others... I guess it's a
> matter of taste. It has to compete against my STRING macro, and Vidar's
> string builder. I *think* that Vidar's less-than-perfect forwarding
> issue can be fixed in C++0x (using std::forward), which would
> *eventually* make his approach superior... Don't you think?

Macros are useful but for this a simple block that is small solves
the namesplash problem and destroys the stringstream on exit. So
it has a name the name does not clash with anything forwarded into the
block and is only visible in the block
std::string out;

{
std::ostrringstream some_name_not_next_statement;
some_name_not_in_next_statement << ... << .... ;
out = some_name_not_next_statement.str();
}

done no macros, no major name chosing problem if the usual chosen name
is used for output just change the ostringstreams name in the
offending block. Doing the same thing a lot use templates or even
consider

template <class T>
std::string & write_to_string(std::string &s, const T &t)
{
std::ostringstream os;
os << t;
return s += os.str();
}

std::string s;
s = write_to_string(s,write_to_string(s,x),y);

writing
std::string & operator << (std::string &,const T &);
might be legal...

Brendan Miller

unread,
Apr 27, 2008, 9:29:25 AM4/27/08
to
On Sat, 26 Apr 2008 08:46:24 CST, Niels Dekker - no return address wrote:

> Vidar Hasfjord wrote:
>> An alternative wrapper solution that I use is based on
>> forwarding the << operator call:
>>
>> struct S { // string builder
>> std::ostringstream s;
>>
>> template <typename T>
>> inline S& operator << (const T& v) {
>> using ::operator <<; // Note: Ugly disambiguation.

Is this using statement really necessary? What ambiguity exists?

People do a using std::swap before calling swap, because if there is no
swap provided by ADL, then we want the default swap to be available.
However, in this case ::operators are always available because they are in
the global namespace.

>> s << v;
>> return *this;
>> }
>> inline operator std::string () const
>> {return s.str ();}
>> };
>>
>> Usage:
>> string s = S () << "i = " << i;
>
> Cool!!! It looks much better than my approach!
>

Yes and much better than mine, which I was proud of up until now. This
strikes me as the One True Way of inline stringbuilding.

>> This works for me in practice. But you may stumble into problems
>> caused by less-than-perfect forwarding (e.g. ambiguities).
>
> Can you please explain?

Yes, I'm iffy on what the problem is here.

>I *think* that Vidar's less-than-perfect forwarding
>issue can be fixed in C++0x (using std::forward), which would
>*eventually* make his approach superior... Don't you think?

I thought std::forward was supposed to help with r-values (although I don't
know the 0X standard that well)? Vidar seems concerned about disambiguating
lookup on << inside of S::<<.

Vidar Hasfjord

unread,
Apr 27, 2008, 9:29:42 AM4/27/08
to
On Apr 26, 3:46 pm, Niels Dekker - no return address

<nore...@this.is.invalid> wrote:
>> inline S& operator << (const T& v) {
>> using ::operator <<; // Note: Ugly disambiguation.
>> [...]

>> This works for me in practice. But you may stumble into problems
>> caused by less-than-perfect forwarding (e.g. ambiguities).
>
> Can you please explain?

The problem is lookup. The application of the << operator inside my
template doesn't cause the same lookup as if it where applied directly
to the stream at the user call site. The operator calls happen in two
different scopes where different entities may be visible.

Usually this isn't a problem though since well-designed operator
overloads rely on argument-dependent lookup (ADL) to find the right
overload; i.e. by putting the operator overload in the same namespace
as the argument type.

It is only a problem where using a stream directly would also cause a
lookup failure. But, while explicit using declarations would solve the
problem in the latter case, it has no effect with my proxy class. For
example,

using foo::bar::operator <<;
ostringstream os; os << foo::t (); // ok
string s = S () << foo::t (); // error

Here the S::operator << implementation will fail to find the
foo::bar::operator << overload for foo::t while direct application
will.

My using ::operator << declaration alleviates the problem in some
cases only, i.e. when the operator can be found in the global
namespace. I went back and looked closer at the particular places in
my code where it was needed, and I've now found better solutions. I
have thus removed the using declaration.

There may also be cases where the operator is ambiguous inside S while
not in the client scope. I've seen this in places where I had many
namespaces opened. More explicit namespace usage resolved the
problems.

> All I can think of is getting into troubles,
> because of an operator<< overload that would have a non-const reference

Sorry, bad use of terminology on my part. I was thinking about lookup
and not argument forwarding. There are solutions to argument
forwarding (such as adding more operator overloads to S). So far I've
not found it an issue; even with that simple single overload.

Regards,
Vidar Hasfjord

Vidar Hasfjord

unread,
Apr 28, 2008, 3:56:19 AM4/28/08
to
On Apr 27, 2:29 pm, Brendan Miller <catph...@catphive.net> wrote:
> >> using ::operator <<; // Note: Ugly disambiguation.
> Is this using statement really necessary? What ambiguity exists?

See my reply to Niels. I was unclear on the reason for the using
statement. As you point out its only use is for disambiguation. The
global namespace is of course always searched, but with the using
declaration any matching global operator becomes the preferred.

I have since removed the using statement because I found better
solutions in the client code were lookup problems occurred.

> >> Usage:
> >> string s = S () << "i = " << i;
>
> > Cool!!! It looks much better than my approach!
>
> Yes and much better than mine, which I was proud of up until now. This
> strikes me as the One True Way of inline stringbuilding.

In the search for the ultimate terseness:

const struct StringBuilderFactory
{
struct StringBuilder
{
std::auto_ptr <std::ostringstream> s;

StringBuilder ()
: s (new std::ostringstream ())
{}

template <typename T>
inline StringBuilder& operator << (const T& v)
{
*s << v;
return *this;
}

inline operator std::string () const

{return s->str ();}
};

template <typename T>
StringBuilder operator << (const T& obj) const
{return StringBuilder () << obj;}
}
S;

Usage:

string s = S << "i = " << i;

Here S is a global instance of StringBuilderFactory. But it has no
state of its own so that's OK. The major drawback with this solution
is that it is slower due to the dynamic allocation of the stream.
Unfortunately dynamic allocation is required here because streams
cannot be copied and hence not returned from StringBuilderFactory. The
next C++ standard, C++0x, will fix this with move constructors for
streams.

If anyone has a C++03 solution to this problem, it would be nice to
see.

Regards,
Vidar Hasfjord

Vidar Hasfjord

unread,
Apr 28, 2008, 4:13:22 AM4/28/08
to
On Apr 27, 2:13 pm, Carl Barron <cbarron...@adelphia.net> wrote:
> Macros are useful but for this a simple block that is small solves
> the namesplash problem and destroys the stringstream on exit.

True, and as a rule I use a sequence of statements when the formatting
is a series of logic steps (i.e. an algorithm). But for simple string
building this is verbose, and more fundamentally, it turns an
expression into statements. I think this is what creates the biggest
craving for an infix solution; not necessarily terseness, although
that comes as a consequence of more elegance in expressions.

Aside: Statements do not compose. E.g. f (g ()) breaks apart and
introduces named types and temporaries if f or g must be expressed as
statements; i.e. R r; f (r); g (r).

> s = write_to_string(s,write_to_string(s,x),y);

This is an expressive solution, but see my reply to Niels for a terser
and more efficient alternative.

Regards,
Vidar Hasfjord

vov...@gmail.com

unread,
Apr 28, 2008, 6:06:27 PM4/28/08
to
On Apr 28, 8:56 am, Vidar Hasfjord <vattila...@yahoo.co.uk>
wrote:

> If anyone has a C++03 solution to this problem, it would be nice to
> see.

This can be done by changing a member


std::auto_ptr <std::ostringstream> s;

with
std::stringstream s;
and defining the copy constructor with
s << sb.s.rdbuf();
in its body. Not sure if this approach is any better.
The StringBuilderFactory would become:

const struct StringBuilderFactory
{
class StringBuilder
{
public:
StringBuilder() {}

StringBuilder(const StringBuilder& sb)
{s << sb.s.rdbuf();}

template <typename T>
inline StringBuilder& operator << (const T& v)
{

s << v;
return *this;
}

inline operator std::string () const

{return s.str();}

private:
std::stringstream s;
};

StringBuilderFactory() {}

template <typename T>
StringBuilder operator << (const T& obj) const
{return StringBuilder () << obj;}

} S;

--

Niels Dekker - no return address

unread,
Apr 28, 2008, 6:01:35 PM4/28/08
to
Brendan Miller wrote:
> People do a using std::swap before calling swap, because if there
> is no swap provided by ADL, then we want the default swap to be
> available.

There's an extra reason for "using std::swap" within the body of a swap
function. Suppose we'd add a swap member function to the latest version of
Vidar's StringBuilder, having an std::auto_ptr member (StringBuilder::s).
Suppose we would write (inline, within the struct definition):

void swap(StringBuilder& arg)
{
swap(this->s, arg.s); // compile error!!!
}

You might expect ADL to find std::swap, because auto_ptr is inside the std
namespace. But instead, it wouldn't compile, because name lookup would find
the member function itself and stop there. When adding "using std::swap", the
member swap would be hidded, and std::swap would be found!

void swap(StringBuilder& arg)
{
using std::swap;
swap(this->s, arg.s); // Okay!
}

So now I don't understand why Vidar's StringBuilder::operator<< compiles
without the using declaration!!!

Vidar Hasfjord wrote:
...


> struct StringBuilder
> {
> std::auto_ptr <std::ostringstream> s;
>

...


> template <typename T>
> inline StringBuilder& operator << (const T& v)
> {
> *s << v;
> return *this;
> }

Why doesn't StringBuilder::operator<< hide other operator<< functions, called
within its own body??? I would expect to get a compile error from doing "*s
<< v"!!!


Thanks again,

Niels

guinne...@gmail.com

unread,
Apr 28, 2008, 6:01:50 PM4/28/08
to
On 23 Apr, 20:14, "Niels Dekker - no return address"

<nore...@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<<).

This is odd. The operator<< that is called here...

> std::string s = (std::ostringstream() << "i = " << i).str();

^^

is member function std::ostream::operator<<(char const*). There is no
case of a temporary being bound to a non-const reference here. It is
perfectly legal and should compile just fine. What compiler are you
using
that complains here (without the .str() business)?

The problem you describe would occur if the argument to operator<<
were not
catered-for by the overloaded set of member functions in
std::basic_ostream
(e.g. if it were a std::string or std::complex<T>.) There is a well-
known
idiom for circumventing this problem (without inventing your wrapper
class)
by using the knowledge that the member-function versions of operator<<
all
return lvalue references; one such member is the one that executes
free
functions whose signatures resemble "std::ostream&
func(std::ostream&)"
as if they were manipulators in the operator<< chain (e.g. std::endl,
std::flush.) The idiomatic approach is to select std::flush for this
job as it has no discernible side-effects; thus:

int i = 42;
std::string prefix = "i = ";
std::ostringstream() << std::flush << prefix << i;

> 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();

As explained above, all this is unnecessary. You should still be
addressing
the single problem in your code as originally presented.

> 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?

Yes, indeed. And since you *know* that the actual object (to whom the
ostream reference refers) is definitely an ostringstream, you can use
static_cast rather than dynamic_cast:

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

> At least, it *seems* to work... But is it the proper way to do it?

Yes.

And if you need to cope with e.g. string objects as the first
item in the operator<< chain, you can also employ the temp-to-lvalue
conversion outlined above, e.g.

int i = 42;
std::string prefix = "i = ";


std::string s = static_cast<std::ostringstream&>(

std::ostringstream() << std::flush << prefix << i).str();

Regards,
Tony.


--

Hendrik Schober

unread,
Apr 28, 2008, 10:35:47 PM4/28/08
to
Vidar Hasfjord <vattila...@yahoo.co.uk> wrote:
> [...]

> const struct StringBuilderFactory
> {
> struct StringBuilder
> {
> std::auto_ptr <std::ostringstream> s;
>
> StringBuilder ()
> : s (new std::ostringstream ())
> {}
>
> template <typename T>
> inline StringBuilder& operator << (const T& v)
> {
> *s << v;
> return *this;
> }
>
> inline operator std::string () const
> {return s->str ();}
> };
>
> template <typename T>
> StringBuilder operator << (const T& obj) const
> {return StringBuilder () << obj;}
> }
> S;
> [...]

Doesn't 'StringBuilderFactory::operator<<()' invoke
'operator<<()' on a temporary object and doesn't in
turn 'StringBuilder::operator<<()' change the object
it is invoked for? And isn't that forbidden? Or am I
missing something here?

> Vidar Hasfjord

Schobi

--
Spam...@gmx.de is never read
I'm HSchober at gmx dot de
"I guess at some point idealism meets human nature and
explodes." Daniel Orner

Vidar Hasfjord

unread,
Apr 29, 2008, 12:38:48 PM4/29/08
to
On Apr 29, 3:35 am, "Hendrik Schober" <SpamT...@gmx.de> wrote:
> Doesn't 'StringBuilderFactory::operator<<()' invoke
> 'operator<<()' on a temporary object and doesn't in
> turn 'StringBuilder::operator<<()' change the object
> it is invoked for? And isn't that forbidden? Or am I
> missing something here?

You are missing the fact that both operators are members, and mutating
member calls on temporaries are allowed.

Regards,
Vidar Hasfjord


--

Brendan Miller

unread,
Apr 29, 2008, 12:43:23 PM4/29/08
to
On Mon, 28 Apr 2008 01:56:19 CST, Vidar Hasfjord wrote:

> On Apr 27, 2:29 pm, Brendan Miller <catph...@catphive.net> wrote:
>>>> using ::operator <<; // Note: Ugly disambiguation.
>> Is this using statement really necessary? What ambiguity exists?
>
> See my reply to Niels. I was unclear on the reason for the using
> statement. As you point out its only use is for disambiguation. The
> global namespace is of course always searched, but with the using
> declaration any matching global operator becomes the preferred.
>
> I have since removed the using statement because I found better
> solutions in the client code were lookup problems occurred.
>
>>>> Usage:
>>>> string s = S () << "i = " << i;
>>
>>> Cool!!! It looks much better than my approach!
>>
>> Yes and much better than mine, which I was proud of up until now. This
>> strikes me as the One True Way of inline stringbuilding.
>
> In the search for the ultimate terseness:
>
> const struct StringBuilderFactory
> {
> struct StringBuilder
> {
> std::auto_ptr <std::ostringstream> s;

Well, if you are confident that RVO is performed, you can get rid of the
auto_ptr and write the copy constructor as
StringBuilder(const StringBuilder& sb);

with no body. However, this will fail if your compiler isn't very agressive
about RVO. In particular, in debug mode of VC9, you get a linker error, but
release mode it links fine. I've seen this trick pulled in GCC to some
effect.

By default I think that the auto_ptr is fine, and definitely more portable,
but if you need to do some optimizing and your compiler supports RVO
(recent GCC and VC++ do if optimization is on), you can use this little
hack to avoid dynamic memory allocation. However, I doubt that the auto_ptr
here will ever become so expensive that it is worth the hack to avoid it.

>
> StringBuilder ()
> : s (new std::ostringstream ())
> {}
>
> template <typename T>
> inline StringBuilder& operator << (const T& v)
> {
> *s << v;
> return *this;
> }
>
> inline operator std::string () const
> {return s->str ();}
> };
>
> template <typename T>
> StringBuilder operator << (const T& obj) const
> {return StringBuilder () << obj;}
> }
> S;
>
> Usage:
>
> string s = S << "i = " << i;

If I try:
S << "asdf" << endl;

For some reason it can't find an overload for << endl.

Vidar Hasfjord

unread,
Apr 29, 2008, 12:43:23 PM4/29/08
to
On Apr 28, 11:06 pm, vova...@gmail.com wrote:
> This can be done by changing a member
> std::auto_ptr <std::ostringstream> s;
> with
> std::stringstream s;
> and defining the copy constructor with
> s << sb.s.rdbuf();
> in its body. Not sure if this approach is any better.

It does remove the need for dynamic allocation of the stream, but it
requires two instances of the stream and copying of the content
between them. Creating instances and copying will involve dynamic
allocation. Hence I doubt it is any more efficient than dynamic
allocation of the stream.

The underlying problem is that ostringstream is not swappable. While I
saw a glimmer of hope in using rdbuf to swap the stringbuffers,
unfortunately a derived stream may use its own buffer (not the one
returned by ios::rdbuf), and unfortunately ostringstream does just
that. It even hides the mutating version of rdbuf, so you cannot
replace the buffer.

A custom stream overcomes this problem:

// Swappable string buffer

class stringbuf
: public std::stringbuf
{
public:
explicit stringbuf ()
: std::stringbuf (std::ios_base::out)
{}

void swap (stringbuf& other) throw ()
{
char* gbegin = other.eback ();
char* gnext = other.gptr ();
char* gend = other.egptr ();
other.setg (eback (), gptr (), egptr ());
setg (gbegin, gnext, gend);

char* pbegin = other.pbase ();
char* pnext = other.pptr ();
char* pend = other.epptr ();
other.setp (pbase (), pptr (), epptr ());
setp (pbegin, pnext, pend);
}
};

// String stream base

typedef std::basic_ostream <char, std::char_traits <char> >
ostringstream_base;

// Swappable string stream

class ostringstream
: public ostringstream_base
{
public:
ostringstream ()
: ostringstream_base (&buf)
{}

void swap (ostringstream& other) throw ()
{buf.swap (other.buf);}

stringbuf* rdbuf()
{return &buf;}

std::string str () const
{return buf.str();}

void str (const std::string& s)
{buf.str (s);}

private:
stringbuf buf;
};

Regards,
Vidar Hasfjord

Vidar Hasfjord

unread,
Apr 29, 2008, 12:43:22 PM4/29/08
to
On Apr 28, 11:01 pm, "Niels Dekker - no return address"

<nore...@this.is.invalid> wrote:
> So now I don't understand why Vidar's StringBuilder::operator<< compiles
> without the using declaration!!!

Careful now; I've heard that trying to understand C++ lookup rules is
hazardous to mental health. :-)

There are apparently different rules for operator application and
ordinary function calls. If you replace (s << v) with (operator << (s,
v)) the lookup will fail as you describe.

I'm not sure this is a good thing though; from a language design
perspective it is a bit irregular.

Regards,
Vidar Hasfjord

vov...@gmail.com

unread,
Apr 29, 2008, 2:13:56 PM4/29/08
to
On Apr 29, 5:43 pm, Vidar Hasfjord <vattilah-gro...@yahoo.co.uk>
wrote:

> It does remove the need for dynamic allocation of the stream, but it
> requires two instances of the stream and copying of the content
> between them. Creating instances and copying will involve dynamic
> allocation. Hence I doubt it is any more efficient than dynamic
> allocation of the stream.
That is right, but default construction of the StringBuilder is
lighter this way when not using the StringBuilderFactory.

> It even hides the mutating version of rdbuf, so you cannot
> replace the buffer.

This is the trouble indeed.

Kind regards,
Vladimir

Vidar Hasfjord

unread,
Apr 29, 2008, 7:41:45 PM4/29/08
to
On Apr 29, 5:43 pm, Brendan Miller <catph...@catphive.net> wrote:
> Well, if you are confident that RVO is performed, you can get rid of the
> auto_ptr and write the copy constructor as
> StringBuilder(const StringBuilder& sb);
> with no body.

Cool, but seems a little brittle.

> By default I think that the auto_ptr is fine, and definitely more portable,
> but if you need to do some optimizing and your compiler supports RVO
> (recent GCC and VC++ do if optimization is on), you can use this little
> hack to avoid dynamic memory allocation. However, I doubt that the auto_ptr
> here will ever become so expensive that it is worth the hack to avoid it.

Agree. And the best solution is to use a string stream with move
support. Writing a custom string stream that provides this is not that
many lines of code. See my reply to vova.

> If I try:
> S << "asdf" << endl;
>
> For some reason it can't find an overload for << endl.

You just have to write (static_cast <ostream& (*) (ostream&)>
(endl)). :-)

The manipulator endl is not just a single function but several
overloads for different types of streams. This creates ambiguity when
trying to match the StringBuilder operator template. You can add
overloads to StringBuilder to deal with this. That said, endl isn't
that useful here, and other manipulators seem to work fine (in VC9; in
VC7.1 I have to take the address of non-parameterized manipulators,
e.g. &fixed).

Regards,
Vidar Hasfjord

Niels Dekker - no return address

unread,
Apr 30, 2008, 12:26:51 PM4/30/08
to
Tony Guinness wrote:
> The operator<< that is called here...
>> std::string s = (std::ostringstream() << "i = " << i).str();
> is member function std::ostream::operator<<(char const*). There is no
> case of a temporary being bound to a non-const reference here. It is
> perfectly legal and should compile just fine.

STLPort has it defined as a non-member!

template <class _Traits>
inline basic_ostream<char, _Traits>& _STLP_CALL
operator<<(basic_ostream<char, _Traits>& __os, const char* __s)

Just look at "stlport/stl/_ostream.h", from
http://www.stlport.com/archive/STLport-5.0RC2.tar.gz

> There is a well-known idiom for circumventing this problem


> (without inventing your wrapper class) by using the knowledge
> that the member-function versions of operator<< all
> return lvalue references; one such member is the one that executes
> free functions whose signatures resemble
> "std::ostream& func(std::ostream&)" as if they were manipulators in
> the operator<< chain (e.g. std::endl, std::flush.) The idiomatic
> approach is to select std::flush for this job as it has no
> discernible side-effects; thus:
>
> int i = 42;
> std::string prefix = "i = ";
> std::ostringstream() << std::flush << prefix << i;

Nice trick! Actually I didn't know that idiom, but I'm certainly not an
STL expert...

>> 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();
>
> As explained above, all this is unnecessary.

Well, I still like to use the Wrapper, because it's a more generic way
to get a "temporary" lvalue reference. It could also be used for types
that don't support the "<< std::flush" idiom. Instead of using my
Wrapper template, you could of course use Boost's value_initialized:

std::string s = (boost::value_initialized<std::ostringstream>().data()
<< "i = " << i).str();

Of course my approach still has to compete against the wonderful
StringBuilderFactory::StringBuilder solution by Vidar Hasfjord...

Anyway, thanks for your suggestion!

Kind regards, Niels

vov...@gmail.com

unread,
Apr 30, 2008, 12:39:18 PM4/30/08
to
On Apr 30, 12:41 am, Vidar Hasfjord <vattilah-gro...@yahoo.co.uk>
wrote:

> Agree. And the best solution is to use a string stream with move
> support. Writing a custom string stream that provides this is not that
> many lines of code. See my reply to vova.
How about separating the StringBuilder from the StringBuilderFactory
and defining a single line macro?

#define S StringBuilder()

The usage stays the same:

string s = S << "i = " << i;

That is if the namespaces are not an issue.

Kind regards,
Vladimir

Vidar Hasfjord

unread,
Apr 30, 2008, 7:04:43 PM4/30/08
to
On Apr 30, 5:39 pm, vova...@gmail.com wrote:
> How about separating the StringBuilder from the StringBuilderFactory
> and defining a single line macro?
>
> #define S StringBuilder()

Short and concise. S is a shorthand. StringBuilderFactory is more
complicated to specify and convey.

> That is if the namespaces are not an issue.

Yes, that's the downfall of the macro solution. A single letter macro
is bound to create havoc sooner or later.

Regards,
Vidar Hasfjord

guinne...@gmail.com

unread,
May 1, 2008, 3:12:58 PM5/1/08
to
On 30 Apr, 17:26, Niels Dekker - no return address
<nore...@this.is.invalid> wrote:
> Tony Guinness wrote:
^^^^^^^^^^^^^
(nice assumption, but wrong - my surname isn't "Guinness";
"Guinness Tony" is a monicker used by my familiars to
distinguish me from those Tonys that don't imbibe the
Black Stuff!)

> > The operator<< that is called here...
> >> std::string s = (std::ostringstream() << "i = " << i).str();
> > is member function std::ostream::operator<<(char const*). There is no
> > case of a temporary being bound to a non-const reference here. It is
> > perfectly legal and should compile just fine.
>
> STLPort has it defined as a non-member!
>
> template <class _Traits>
> inline basic_ostream<char, _Traits>& _STLP_CALL
> operator<<(basic_ostream<char, _Traits>& __os, const char* __s)
>
> Just look at "stlport/stl/_ostream.h", fromhttp://www.stlport.com/archive/STLport-5.0RC2.tar.gz

My mistake. I really should consult the Standard before making such
rash claims. The C-style string insertion operators are, indeed,
defined as free function templates in [lib.ostream]27.6.2.1:

namespace std {
...


template<class charT, class traits>
basic_ostream<charT,traits>&
operator<<(basic_ostream<charT,traits>&,

const charT*);


template<class charT, class traits>
basic_ostream<charT,traits>&
operator<<(basic_ostream<charT,traits>&,
const char*);

// partial specializationss
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
const char*);
// signed and unsigned
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
const signed char*);
template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&,
const unsigned char*);
}

[how odd - I've never noticed that "specializationss" typo before!]

Sorry to have added unnecessary confusion to the discussion.

Nevertheless, your example still compiles under the toolsets I have
to hand...

int i = 42;


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

...but, on execution, I find that the operator<< chosen by the
compiler
is std::ostream::operator<<(const void*), which /is/ a member function
(I checked this time!) The text written into the stringstream's
string buffer is not a copy of the string literal, but a
representation
of /the address of/ that string literal.

The STLPort implementation that you cited also has the (const void*)
inserter as a member function, so I'm still perplexed as to why your
compiler baulked at it.

In conclusion, the "flush trick" I presented in my previous post is
also required when the first item in the insert-chain is a C-style
string (including string literals), i.e.

int i = 42;


std::string s = static_cast<std::ostringstream&>(

std::ostringstream() << std::flush << "i = " << i).str();

Cheers,
Tony.

Niels Dekker - no return address

unread,
May 2, 2008, 2:45:30 PM5/2/08
to
Tony (aka "Guinness Tony") wrote:
> The C-style string insertion operators are, indeed,
> defined as free function templates in [lib.ostream]27.6.2.1:
>
> namespace std {
> ...
> template<class charT, class traits>
> basic_ostream<charT,traits>&
> operator<<(basic_ostream<charT,traits>&,
> const charT*);
> template<class charT, class traits>
> basic_ostream<charT,traits>&
> operator<<(basic_ostream<charT,traits>&,
> const char*);
> // 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


> Sorry to have added unnecessary confusion to the discussion.

No problem. I was mistaken as well, when I wrote:
>>
>> 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<<).

Only after seeing the reply by Vidar Hasfjord, I double-checked, and found
that my toolset actually accepted inserting a literal string onto a temporary
stream, because it had offered that specific operator<< as a member
function!!! (I wasn't using STLPort.)


> Nevertheless, your example still compiles under the toolsets I have
> to hand...
>
> int i = 42;
> std::string s = static_cast<std::ostringstream&>(
> std::ostringstream() << "i = " << i).str();
>
> ...but, on execution, I find that the operator<< chosen by the
> compiler is std::ostream::operator<<(const void*), which /is/ a
> member function (I checked this time!) The text written into
> the stringstream's string buffer is not a copy of the string
> literal, but a representation of /the address of/ that string
> literal.

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


> In conclusion, the "flush trick" I presented in my previous post is
> also required when the first item in the insert-chain is a C-style
> string (including string literals), i.e.
>
> int i = 42;
> std::string s = static_cast<std::ostringstream&>(
> std::ostringstream() << std::flush << "i = " << i).str();

Still, why do you think the "flush trick" is superior to creating a
"temporary" lvalue by means of a wrapper? Do you have any references, showing
that the "flush trick" is indeed a well-known idiom? (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.)
Otherwise I think I'll stick to the wrapper...


Kind regards, Niels

guinne...@gmail.com

unread,
May 7, 2008, 1:43:29 PM5/7/08
to
On 2 May, 19:45, "Niels Dekker - no return address"

<nore...@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.

Niels Dekker - no return address

unread,
May 8, 2008, 11:29:05 PM5/8/08
to
>> Do you have any references, showing
>> that the "flush trick" is indeed a well-known idiom?

Tony replied:


> 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/

Thanks for the link to that "std::ostringstream misunderstanding" thread! I
hadn't read it yet!


> "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 [...] )

> 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.

Good point. The thread also has a link to a relevant paragraph of a paper by
Howard Hinnant, Dave Abrahams, and Peter Dimov:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html#Use%20of%20Rvalue%20Streams
Which says:
As a workaround, many people instead code:
...
std::ofstream("Log file", std::ios::app).flush() << "Log message\n";
...
The ".flush()" is a no-op that simply changes the rvalue ofstream
into an lvalue.

So if many people do it like that, I guess you were right, and it /is/
idiomatic after all. Or maybe we should call it "an idiomatic curiosity" ;-)


Kind regards,

Niels

0 new messages