Topic: Simple C++ that just fails to do what it is supposed to


Author: Seungbeom Kim <musiphil@bawi.org>
Date: Wed, 17 Jan 2007 09:39:45 CST
Raw View
Michael Goldshteyn wrote:
> The following message started in comp.lang.c++, but a suggestion was made
> that this would be the more appropriate group:
>
> Consider the following two lines of code, the first intended to print "Hello
> world\n" and the second intended to print the character 'P' to stdout.
>
> ---
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> "Hello world\n").str();
>
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> 'P').str();
> ---
>
> Instead, the first line print the address of the string literal "Hello
> world\n" and the second prints the ASCII value of 'P', 80.
>
> I would like a meaningful discussion as to why this is happening. It appears
> that in the first case, the const char * that is the string literal is being
> interpreted in void * context and in the second case, the character is
> somehow being interpreted as an int.

I believe that issue has been discussed many times over the years.

Quoted from
<http://groups.google.com/group/comp.lang.c++.moderated/msg/66e6c1a9f007d8a2>:
> ostringstream() is a temporary object, *not* an lvalue,
> so it cannot bind to the first parameter of the non-member function
> operator<<(ostream&, const char*), so the member function ostream::
> operator<<(const void*) will be used instead, which just prints the
> address of the pointer.

and a workaround and the future solution is also mentioned in the message.

--
Seungbeom Kim

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: "James Kanze" <james.kanze@gmail.com>
Date: Wed, 17 Jan 2007 09:51:48 CST
Raw View
"Michael Goldshteyn" wrote:
> The following message started in comp.lang.c++, but a suggestion was made
> that this would be the more appropriate group:

> Consider the following two lines of code, the first intended to print "Hello
> world\n" and the second intended to print the character 'P' to stdout.

> ---
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> "Hello world\n").str();

> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> 'P').str();
> ---

> Instead, the first line print the address of the string literal "Hello
> world\n" and the second prints the ASCII value of 'P', 80.

> I would like a meaningful discussion as to why this is happening. It appears
> that in the first case, the const char * that is the string literal is being
> interpreted in void * context and in the second case, the character is
> somehow being interpreted as an int.

There's nothing meaningful about it; it's what the standard
requires.  Basically, some of the << overloads are members,
others aren't.  When outputting to a temporary (your
std::ostringstream()), the non-members are not considered, since
calling them would entail binding the temporary to a non-const
reference.  Calling a non-const function on a temporary is
allowed, however, so you do find the member overloads.  As it
happens, for some strange reason (breaking compatibility with
the classic IO stream), << for char const* and for char are not
members, and so aren't considered.

The classical way of getting a non-const reference to bind to
the non-members was << "", outputting a char const* which
corresponded to the empty string.  The standard equivalent of
this is to call flush, e.g.:

    std::cout << (std::ostringstream().flush() << "Hello
world\n").str() ;

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: Howard Hinnant <howard.hinnant@gmail.com>
Date: Wed, 17 Jan 2007 10:17:01 CST
Raw View
In article <9ZmdnSFMG-pVszDYnZ2dnUVZ_vCknZ2d@giganews.com>,
 "Michael Goldshteyn" <mgoldshteyn@comcast.net> wrote:

> The following message started in comp.lang.c++, but a suggestion was made
> that this would be the more appropriate group:
>
> Consider the following two lines of code, the first intended to print "Hello
> world\n" and the second intended to print the character 'P' to stdout.
>
> ---
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> "Hello world\n").str();
>
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> 'P').str();
> ---
>
> Instead, the first line print the address of the string literal "Hello
> world\n" and the second prints the ASCII value of 'P', 80.
>
> I would like a meaningful discussion as to why this is happening. It appears
> that in the first case, the const char * that is the string literal is being
> interpreted in void * context and in the second case, the character is
> somehow being interpreted as an int.

The reason this is happening is because the operators taking void* and
int are members of basic_ostream while the operators taking const char*
and char are non-members.  The non-member operators take their stream
parameters by non-const reference.  Since your streams are rvalues, they
can not bind to the non-const reference of the non-member operators.
But they can bind to the indicated member functions with appropriate
conversions on the second arguments.

The rvalue reference work seeks to correct this situation by adding
non-member overloads which take the basic_ostream by rvalue reference,
thus allowing binding to an rvalue.  For example:

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

This application of the rvalue reference is introduced here:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html#Use%20
of%20Rvalue%20Streams

And the proposed wording for it is provided here:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1862.html

The proposed wording in N1862 has not yet been voted into the working
draft, but my current impression is that it has strong support.

N1690 has a type-o in its example use of ostringstream.  The cast back
to ostringstream& was accidently omitted.  Your example code is the
correct formulation and will work as you would like if this proposal is
accepted (your code actually tested on the CodeWarrior prototype).

-Howard

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: no.spam@no.spam.com (Maciej Sobczak)
Date: Wed, 17 Jan 2007 16:50:20 GMT
Raw View
Michael Goldshteyn wrote:

> The following message started in comp.lang.c++, but a suggestion was made
> that this would be the more appropriate group:
>
> Consider the following two lines of code, the first intended to print "Hello
> world\n" and the second intended to print the character 'P' to stdout.
>
> ---
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> "Hello world\n").str();
>
> std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
> 'P').str();
> ---
>
> Instead, the first line print the address of the string literal "Hello
> world\n" and the second prints the ASCII value of 'P', 80.
>
> I would like a meaningful discussion as to why this is happening.

Search the comp.lang.c++.moderated group for the thread "Stream behavior
that I don't understand" from November last year - something similar was
discussed there.

The short story is that the stream object is a temporary and cannot be
bound to non-const reference that free overloaded << operators have as
their left parameter. That's why the operator<< for strings and
operator<< for chars are excluded and the only operators that are left
for consideration are those which are member functions in the ostream
class. Among these, there is operator<< for void* (first case) and
operator<< for int (second case).

See 27.6.2.1 to get the idea of which operator is a member function (and
can be called on a temporary stream object) and which is a free function
(and has a non-const reference as the left parameter).


--
Maciej Sobczak : http://www.msobczak.com/
Programming    : http://www.msobczak.com/prog/

---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: giecrilj@stegny.2a.pl ("Kristof Zelechovski")
Date: Mon, 22 Jan 2007 05:21:49 GMT
Raw View
Uzytkownik "Seungbeom Kim" <musiphil@bawi.org> napisal w wiadomosci
news:eojn7t$6ph$1@news.Stanford.EDU...
> Quoted from
> <http://groups.google.com/group/comp.lang.c++.moderated/msg/66e6c1a9f007d8a2>:
>> ostringstream() is a temporary object, *not* an lvalue,
>> so it cannot bind to the first parameter of the non-member function
>> operator<<(ostream&, const char*), so the member function ostream::
>> operator<<(const void*) will be used instead, which just prints the
>> address of the pointer.
>
> and a workaround and the future solution is also mentioned in the message.
>
> --
> Seungbeom Kim

Regarding the workaround:

class C { typedef C &ref; public: ref yourself() { return *this; } };
C (&g_c)(C().yourself());
Is this a reference bound to a temporary in the sense of
[class.temporary]/2?
Otherwise, the following statement of [class.temporary]/5 looks suspicious:

A temporary bound to the returned value in a function return statement
(6.6.3) persists until the function exits.



The argument is that the the body of ostream::flush() binds a temporary
ostrstream() to the return value,

so the temporary ostrstream() persists until the function ostream::flush()
exits,

which means that the reference is invalid afterwards

and cannot serve as an argument to

operator << <ostream::char_type, ostream::traits_type>(ostream &,
ostream::char_type const []).

Alternatively, that sentence should read



A temporary bound to the returned value in a function return statement
(6.6.3) persists at least until the function exits.



Moreover, I am not sure what this statement practically means,

except that the destructor of the temporary is invoked after the destructors
of all automatic variables local to the function,

but before the reference is initialized.

To make matters worse, it seems the temporary object cannot be created
within the function, it must be passed to it by reference.



Example:



extern Tconst &foo(void) { return T(); }


Can the return value of such a function be used for any purpose
except sizeof, (void) and accessing static members of T?  I doubt.
The question is what use cases this statement is meant to cover.
If it is meant to cover

extern T foo(void) { return T(); }

then the temporary is copied and not bound, so this statement does not
apply.
Or does it  refer to copy elimination as defined in [class.copy]/15?
But copy elimination means that no temporary is created, so it does not
apply either.

:-b (after two hours of fruitless meditation)
Chris


---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]





Author: mgoldshteyn@comcast.net ("Michael Goldshteyn")
Date: Tue, 16 Jan 2007 21:46:59 GMT
Raw View
The following message started in comp.lang.c++, but a suggestion was made
that this would be the more appropriate group:

Consider the following two lines of code, the first intended to print "Hello
world\n" and the second intended to print the character 'P' to stdout.

---
std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
"Hello world\n").str();

std::cout << static_cast<std::ostringstream &>(std::ostringstream() <<
'P').str();
---

Instead, the first line print the address of the string literal "Hello
world\n" and the second prints the ASCII value of 'P', 80.

I would like a meaningful discussion as to why this is happening. It appears
that in the first case, the const char * that is the string literal is being
interpreted in void * context and in the second case, the character is
somehow being interpreted as an int.

Thanks,

Mike



---
[ 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://www.comeaucomputing.com/csc/faq.html                      ]