Topic: unnamed objects and conversions


Author: James Kanze <kanze@gabi-soft.de>
Date: Mon, 21 Jan 2002 08:30:15 GMT
Raw View
Adam Peterson <ahp6@email.byu.edu> writes:

|>  > The conversion of relevance is the conversion of a char const* to an
|>  > std::ofstream.  Whether you write:
|>  >     std::ofstream( "file" ),
|>  >     (std::ofstream)"file", or
|>  >     static_cast< std::ofstream >( "file" )
|>  > the signification is the same: convert the char const[5] into an
|>  > std::ofstream.  The conversion uses a single argument constructor,
|>  > which means that it is a user-defined conversion.

|>  I believe, from my reading of the standard (27.8.1.8) that since the
|>  constructor being called is explicit, only the first form should work.

Possible.  I can never keep all of these subtilities separate, but my
understanding was that all of these specified an explicit conversion.
The reference in 12.3.1/2 concerning where explicit constructors can be
used is simply says "where casts are explicitly used", and refers to
both 5.2.9 and 5.4.  (Curiously, these references cover cases 2 and 3,
but not case 1.  But 5.2.3/1 says that if there is only a single
argument, case 1 is the equivalent of 5.4.)

--
James Kanze                                mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)179 2607481

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: James Kanze <kanze@gabi-soft.de>
Date: Mon, 21 Jan 2002 08:30:36 GMT
Raw View
jpotter@falcon.lhup.edu (John Potter) writes:

|>  On Wed, 16 Jan 2002 16:02:59 GMT, kanze@gabi-soft.de (James Kanze)
|>  wrote:

|>  > case of the standard, I rather wonder why char const* should be an
|>  > exception; I guess they wanted it to parallel what happened with
|>  > std::string (which is also a non-member).

|>  I wonder if this had anything to do with it.

|>     <<(os<charT>, charT)
|>     <<(os<charT>, char)
|>     <<(os<char>, char)
|>     <<(os<char>, unsigned char)
|>     <<(os<char>, signed char)

|>  Same for the *'s.  Can that be done with members?

I'm not sure I get your point.  What can't be done with members?  How
are these different from the case of int or long, which are members?

--
James Kanze                                mailto:kanze@gabi-soft.de
Conseils en informatique orient   e objet/
                    Beratung in objektorientierter Datenverarbeitung
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany Tel. +49(0)179 2607481

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Mon, 21 Jan 2002 17:52:47 GMT
Raw View
On Mon, 21 Jan 2002 08:30:36 GMT, James Kanze <kanze@gabi-soft.de>
wrote:

> jpotter@falcon.lhup.edu (John Potter) writes:

> |>  On Wed, 16 Jan 2002 16:02:59 GMT, kanze@gabi-soft.de (James Kanze)
> |>  wrote:

> |>  > case of the standard, I rather wonder why char const* should be an
> |>  > exception; I guess they wanted it to parallel what happened with
> |>  > std::string (which is also a non-member).

> |>  I wonder if this had anything to do with it.

> |>     <<(os<charT>, charT)
> |>     <<(os<charT>, char)
> |>     <<(os<char>, char)
> |>     <<(os<char>, unsigned char)
> |>     <<(os<char>, signed char)

> |>  Same for the *'s.  Can that be done with members?

> I'm not sure I get your point.  What can't be done with members?  How
> are these different from the case of int or long, which are members?

The general ostream<charT> supports only charT and char.  The
ostream<char> partial specialization supports char, unsigned char, and
signed char, but not any other charT.  I have ignored traits which may
add more problems.

John

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Frode.Nilsen@mison.no
Date: Tue, 15 Jan 2002 15:12:36 GMT
Raw View
Hi,
I hope someone could give a clear description about correct behaviour for
the following simple code ;)

ofstream( "file" ) << "text1" << "text2";


My current compiler writes something like "0x123abdeftext2" to the file
because it won't use the global operator << for the first call (only the
second).

When I confronted the compiler vendor with this he referred to standard
paragraph 13.3.3.1.4/3 and said that was the cause.

I can't find that correct, because by reading that paragraph and paragraph
1 I can't see that the line should have compiled at all.

But in 13.3.3.1/6 (last part) it states that derived-to-base Conversion is
not a conversion, just included to make the description complete. And by
that I can't se that 13.3.3.1.4/3 has any relevance (a conversion has not
to be formed).


Anyone with a clear interpration of this ?

BTW, what would be a sensible error message to

operator << ( ofstream( "file" ), "text" );

if that isn't allowed to compile ?

sincerely
frode

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Wed, 16 Jan 2002 01:36:35 GMT
Raw View
On Tue, 15 Jan 2002 15:12:36 GMT, Frode.Nilsen@mison.no wrote:

> I hope someone could give a clear description about correct behaviour for
> the following simple code ;)

> ofstream( "file" ) << "text1" << "text2";

This temporary is an rvalue.  It may not be bound to a non-const
reference.

> My current compiler writes something like "0x123abdeftext2" to the file
> because it won't use the global operator << for the first call (only the
> second).

That is because the global operator<< requires an lvalue.  Since that is
not a viable function, the remaining member function operator<<(void
const*) is selected and the value of the char* is output.  Now this
nice member function returns an lvalue and the global operator may be
used for the second char*.

> BTW, what would be a sensible error message to
>
> operator << ( ofstream( "file" ), "text" );
>
> if that isn't allowed to compile ?

Lvalue required.

Your need a hack.

ofstream( "file" ).flush() << "text1" << "text2";

John

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: kanze@gabi-soft.de (James Kanze)
Date: Wed, 16 Jan 2002 16:02:59 GMT
Raw View
Frode.Nilsen@mison.no wrote in message
news:<Frode.Nilsen-1501021009500001@morgan.mison.no>...

> I hope someone could give a clear description about correct
> behaviour for the following simple code ;)

> ofstream( "file" ) << "text1" << "text2";

> My current compiler writes something like "0x123abdeftext2" to the
> file because it won't use the global operator << for the first call
> (only the second).

That is correct.

> When I confronted the compiler vendor with this he referred to
> standard paragraph 13.3.3.1.4/3 and said that was the cause.

> I can't find that correct, because by reading that paragraph and
> paragraph 1 I can't see that the line should have compiled at all.

The key is whether the operator is a member or not.  The expression
ofstream("file") is an rvalue object.  Rvalues cannot bind to
non-const references, but you can call a non-const member function on
an rvalue.  If the operator<< is a free function (as it is for char
const*), the ofstream object cannot be bound to the first parameter
(which has type ostream&), see 8.5.3/5.  For this reason, the << for
char const* doesn't make it into the list of viable functions, see
particularly 13.3.2/3.  If the operator<< is a member function (as it
is for void const*, which displays the address), however, it can be
called on the rvalue, and does make it into the list of viable
functions.  Since there are no other viable functions (char const* can
be implicitly converted into void const*, but not into any of the
other types handled by member functions), the call is unambiguous, but
not the one you want.

Historically, the classical ostream class never defined which
operator<< were members, and which were global functions, so this code
was never guaranteed to work.  In practice, however, all of the
implementations I've seen made the char const* operator a member, and
it was a more or less standard trick to always start your output to a
temporary with an empty string, in order to avoid the problem.  In the
case of the standard, I rather wonder why char const* should be an
exception; I guess they wanted it to parallel what happened with
std::string (which is also a non-member).

> But in 13.3.3.1/6 (last part) it states that derived-to-base
> Conversion is not a conversion, just included to make the
> description complete. And by that I can't se that 13.3.3.1.4/3 has
> any relevance (a conversion has not to be formed).

The conversion of relevance is the conversion of a char const* to an
std::ofstream.  Whether you write:
    std::ofstream( "file" ),
    (std::ofstream)"file", or
    static_cast< std::ofstream >( "file" )
the signification is the same: convert the char const[5] into an
std::ofstream.  The conversion uses a single argument constructor,
which means that it is a user-defined conversion.

> Anyone with a clear interpration of this ?

> BTW, what would be a sensible error message to

> operator << ( ofstream( "file" ), "text" );

> if that isn't allowed to compile ?

It's not allowed to compile.  A typical error message will probably
start with something like "No match for ...".  This is very sensible
from the compiler's point of view; it must invoke function overload
resolution, and the result of the resolution is that none of the
functions match.

To give anything better, the compiler has to redo the resolution
allowing rvalues to bind to non-const references.  If that works, and
the precedent overload resolution didn't, it can then issue a very
precise error message.  Or even reduce the error message to a warning,
and allow it as an extension.  (Some years back, most compilers did do
this, because there was still existing code which depended on earlier
rules which allowed it.)

--
James Kanze                                   mailto:kanze@gabi-soft.de
Beratung in objektorientierer Datenverarbeitung --
                             -- Conseils en informatique orient   e objet
Ziegelh   ttenweg 17a, 60598 Frankfurt, Germany, T   l.: +49 (0)69 19 86 27

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Michiel.Salters@cmg.nl (Michiel Salters)
Date: Wed, 16 Jan 2002 18:21:22 GMT
Raw View
Frode.Nilsen@mison.no wrote in message news:<Frode.Nilsen-1501021009500001@morgan.mison.no>...
> Hi,
> I hope someone could give a clear description about correct behaviour for
> the following simple code ;)
>
> ofstream( "file" ) << "text1" << "text2";
>
>
> My current compiler writes something like "0x123abdeftext2" to the file
> because it won't use the global operator << for the first call (only the
> second).
>
> When I confronted the compiler vendor with this he referred to standard
> paragraph 13.3.3.1.4/3 and said that was the cause.

Which says that T() @ rhs; only calls T::operator@ and no global
operator@.

> I can't find that correct, because by reading that paragraph and paragraph
> 1 I can't see that the line should have compiled at all.

basic_ostream has a member operator<<( const void* ); it is the only viable
function. The first (implicit) parameter can be converted, the second
parameter can be converted, what's the reason it should not compile?

> But in 13.3.3.1/6 (last part) it states that derived-to-base Conversion is
> not a conversion, just included to make the description complete. And by
> that I can't se that 13.3.3.1.4/3 has any relevance (a conversion has not
> to be formed).

13.3.3.1/5 mentions that if the parameter is a reference type, as it is
for the first parameter of global operator<<, 13.3.3.1.4 applies instead
of 13.3.3.1/6.

But yes, I do think this is unfortunate. It might even warrant a library
Defect Report, to add operator<<(charT const*) to basic_ostream. It's at
the least a piece of code to consider for C++0x; too hard to explain to
newbies.

> BTW, what would be a sensible error message to
>
> operator << ( ofstream( "file" ), "text" );
>
> if that isn't allowed to compile ?

"No member operator<< found which can take an argument of type const char*" ?
( Assuming operator<<(const void*) didn't exist )

Regards,

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Adam Peterson <ahp6@email.byu.edu>
Date: Wed, 16 Jan 2002 18:33:06 GMT
Raw View
> The conversion of relevance is the conversion of a char const* to an
> std::ofstream.  Whether you write:
>     std::ofstream( "file" ),
>     (std::ofstream)"file", or
>     static_cast< std::ofstream >( "file" )
> the signification is the same: convert the char const[5] into an
> std::ofstream.  The conversion uses a single argument constructor,
> which means that it is a user-defined conversion.

I believe, from my reading of the standard (27.8.1.8) that since the
constructor being called is explicit, only the first form should work.

I could be wrong, though.  I don't recall the last time I saw James wrong.

Adam Peterson


---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Wed, 16 Jan 2002 23:38:59 GMT
Raw View
On Wed, 16 Jan 2002 16:02:59 GMT, kanze@gabi-soft.de (James Kanze)
wrote:

> case of the standard, I rather wonder why char const* should be an
> exception; I guess they wanted it to parallel what happened with
> std::string (which is also a non-member).

I wonder if this had anything to do with it.

   <<(os<charT>, charT)
   <<(os<charT>, char)
   <<(os<char>, char)
   <<(os<char>, unsigned char)
   <<(os<char>, signed char)

Same for the *'s.  Can that be done with members?

John

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Frode.Nilsen@mison.no
Date: Thu, 17 Jan 2002 17:43:40 GMT
Raw View
Thank you for a comprehensive posting (it gave me an instant headache though ;)

In article <d6651fb6.0201160634.25d79b9e@posting.google.com>,
kanze@gabi-soft.de (James Kanze) wrote:

> Frode.Nilsen@mison.no wrote in message
> news:<Frode.Nilsen-1501021009500001@morgan.mison.no>...
>
> > I hope someone could give a clear description about correct
> > behaviour for the following simple code ;)
>
> > ofstream( "file" ) << "text1" << "text2";
>
> > My current compiler writes something like "0x123abdeftext2" to the
> > file because it won't use the global operator << for the first call
> > (only the second).
>
> That is correct.
>
> > When I confronted the compiler vendor with this he referred to
> > standard paragraph 13.3.3.1.4/3 and said that was the cause.
>
> > I can't find that correct, because by reading that paragraph and
> > paragraph 1 I can't see that the line should have compiled at all.
>
> The key is whether the operator is a member or not.  The expression
> ofstream("file") is an rvalue object.  Rvalues cannot bind to
> non-const references, but you can call a non-const member function on
> an rvalue.  If the operator<< is a free function (as it is for char
> const*), the ofstream object cannot be bound to the first parameter
> (which has type ostream&), see 8.5.3/5.  For this reason, the << for
> char const* doesn't make it into the list of viable functions, see
> particularly 13.3.2/3.  If the operator<< is a member function (as it
> is for void const*, which displays the address), however, it can be
> called on the rvalue, and does make it into the list of viable
> functions.  Since there are no other viable functions (char const* can
> be implicitly converted into void const*, but not into any of the
> other types handled by member functions), the call is unambiguous, but
> not the one you want.
>

I haven't been able to digest on all the follow-up postings, but I haven't
seen any suggesting the simple solution to use a cast for the problem,
like:

(ostream&)ofstream( "file" ) << "text1" << "text2";

Is this because it shouldn't work (as it does on my compiler), or is it
that the cast is converting the rvalue to a lvalue (which I didn't think
was allowed)?

Or are there other rules that I am completely unaware of (as always)?

Thanks to everyone, if someone could explain this last issue I can
hopefully have a weekend with peace in mind.



frode

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Frode.Nilsen@mison.no
Date: Fri, 18 Jan 2002 16:05:28 GMT
Raw View
In article <d6651fb6.0201160634.25d79b9e@posting.google.com>,
kanze@gabi-soft.de (James Kanze) wrote:

>
> > BTW, what would be a sensible error message to
>
> > operator << ( ofstream( "file" ), "text" );
>
> > if that isn't allowed to compile ?
>
> It's not allowed to compile.  A typical error message will probably
> start with something like "No match for ...".  This is very sensible
> from the compiler's point of view; it must invoke function overload
> resolution, and the result of the resolution is that none of the
> functions match.
>
> To give anything better, the compiler has to redo the resolution
> allowing rvalues to bind to non-const references.  If that works, and
> the precedent overload resolution didn't, it can then issue a very
> precise error message.  Or even reduce the error message to a warning,
> and allow it as an extension.  (Some years back, most compilers did do
> this, because there was still existing code which depended on earlier
> rules which allowed it.)
>
> --

OK, I start to understand the problem here, but my compiler spit out a
list of every ostream& operator << ( ostream&, wathever char ) it couldn't
match. And then I started to get confused.
Since it could do that I assume that it could as well have reported
"lvalue required" ? which would have put me on the right track from the
begining.

Again, thanks for all your help.


sincerely
Frode Nilsen

---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: Michiel.Salters@cmg.nl (Michiel Salters)
Date: Fri, 18 Jan 2002 11:50:35 CST
Raw View
Frode.Nilsen@mison.no wrote in message news:<Frode.Nilsen-1701021534150001@morgan.mison.no>...
> I haven't been able to digest on all the follow-up postings, but I haven't
> seen any suggesting the simple solution to use a cast for the problem,
> like:
>
> (ostream&)ofstream( "file" ) << "text1" << "text2";
>
> Is this because it shouldn't work (as it does on my compiler), or is it
> that the cast is converting the rvalue to a lvalue (which I didn't think
> was allowed)?

Not allowed; (T&)T() would require the binding of a temporary T() to
a non-const T&.

Regards,

---
[ 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.research.att.com/~austern/csc/faq.html                ]