Topic: <iostream> not working as planned...


Author: Graeme Prentice <gp1@paradise.net.nz>
Date: 27 Jan 2003 05:35:22 -0500
Raw View
On 25 Jan 03 13:37:08 GMT, kanze@gabi-soft.de (James Kanze) wrote:

>
>The question isn't so much about <iosfwd>, as about the presence of
>operator overloading on an incomplete type.  The article in
>comp.lang.c++.moderated I was responding to seemed to think that it was
>illegal -- the more I think of it, the less I know why.  But his idea
>was that since the compiler couldn't see the overloads of operator<< in
>ostream, it should refuse to do overload resolution.
>

I made that post slightly hastily and after making it, I immediately
posted a question in this newsgroup about 13.3.1.2 para 3 bullet 1 where
it says ...

"If T1 is a class type, the set of member candidates is the result of
the qualified lookup of T1::operator@ (13.3.1.1.1); otherwise, the set
of member candidates is empty. "

In my opinion, it's not immediately obvious that T1 is allowed to be
incomplete here and I jumped to the conclusion that it needed to be
complete.  Fairly soon after, I decided to ask the question in this
newsgroup.  The Borland compiler gives an error for the following code
- maybe other compilers do too.  IMO it's worth adding a sentence to
13.3.1.2 that says an incomplete type T1 is allowed  -  this may help
produce consistency among compilers for this.  I intend posting a defect
report here as soon as I get round to it.

class c1;
extern c1 o1;
void operator<<( c1&, int );

int main()
{
    o1 << 23;
}


Graeme
---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: 25 Jan 03 13:37:08 GMT
Raw View
allan_w@my-dejanews.com (Allan W) wrote in message
news:<7f2735a5.0301221046.282f54a2@posting.google.com>...
> kanze@gabi-soft.de (James Kanze) wrote
> > Interesting point.  So given the following:

> >     #include <iosfwd>

> >     struct MyClass ;
> >     extern std::ostream& operator<<( std::ostream&, MyClass const& ) ;

> >     void
> >     f( ostream& dest, MyClass const& obj )
> >     {
> >         dest << obj ;
> >     }

> > do I get a (required) compiler error, is it undefined behavior, or
> > ... ?

> > Now how about:

> >     #include <iosfwd>

> >     struct MyClass { MyClass( const char* ) ; } ;
> >     extern std::ostream& operator<<( std::ostream&, MyClass const& ) ;

> >     void
> >     f( ostream& dest )
> >     {
> >         dest << "Hello, world" ;
> >     }

> > Again, required diagnostic, undefined behavior, or ... ?

> > I rather think that this is a question for comp.std.c++.  I've
> > cross-posted; I'd set the follow-ups as well, but Google won't let
> > me.

> I always thought that <iosfwd> was designed to let you declare
> functions which take a reference to (say) an ostream, rather than
> allowing you to operate on that ostream.

The question isn't so much about <iosfwd>, as about the presence of
operator overloading on an incomplete type.  The article in
comp.lang.c++.moderated I was responding to seemed to think that it was
illegal -- the more I think of it, the less I know why.  But his idea
was that since the compiler couldn't see the overloads of operator<< in
ostream, it should refuse to do overload resolution.

The original problem was that <iostream> might not define ostream.  My
reading of the standard is that the intent was more or less that
<iostream> would only include <iosfwd>, with forward definitions of
ostream.  In this case, given something line the latter, you would get a
very surprising overload.

> So this would be legal:

>     // MyClass.h
>     #include <iosfwd>
>     class MyClass {
>        int i;
>        // ...
>     };
>     ostream &operator<<(ostream&, const MyClass&);

> But this would not be, unless we added #include <iostream>:

>     // MyClass.cpp
>     #include "MyClass.h"
>     ostream &operator<<(ostream&out, const MyClass&c) {
>         return out << i; // Error -- ostream is an incomplete class!
>     }

I don't see why including <iostream> would change anything here.
<iostream> doesn't define ostream; that's <ostream>'s job.

Where the question becomes somewhat complicated is if <iostream> for
some reason does happen to define ostream, but doesn't define the global
<< operators.

And there is also the bothersome case where the implementor forgets to
include <ostream> (in his .cpp), but has a constructor taking a single
int.  Since (as far as I can tell) there is no problem on overloading on
the incomplete type, and since the only << operator the compiler sees is
the one for MyClass, there is no compiler error (nor warning, normally),
and the programmer gets to track down an infinite recursion.  (Not that
that is a real problem.  I regularly get hit when defining | operators
for enum types -- I forget to cast one of the operands to an int, so the
compiler invokes my operator recursively.)

> > > Since the non member operator<< functions are required to be in
> > > the ostream header along with basic_ostream class definition it
> > > shouldn't be possible to use cout << anything without getting all
> > > of the std operator<< functions or a compile time error.

> > I think I agree for a correct program.  The initial example is not,
> > IMHO, a correct program, because it uses << without including
> > <ostream>.  I suspect, however, there there are (and will be) a lot
> > more incorrect programs that we'd like.  Incorrect programs which
> > will still work on most implementations.

> > I've very curious about the meaning of my two sample programs; I
> > rather suspect that as people become used to the new headers, the
> > first example will become rather frequent -- don't include more than
> > you have to, which means using <iosfwd> most of the time in headers.
> > The second case is, IMHO, decidedly incorrect, since the header
> > which contains the desired operator overload is not included.  But I
> > suspect that it will occur from time to time.  I'd like to see it be
> > a compiler error, but I can't quite see how to implement it if it
> > is, and <iosfwd> is to remain useful.

> I think both of your examples could be illegal, without making
> <iosfwd> useless.

My question had nothing to do with the utility of <iosfwd>; my question
was were both (or either) example illegal.  I don't think either was.  I
think that the first example is useful, but that if people actually
start using the new headers as they were obviously meant to be used, the
second will lead to some surprising behavior -- it's a programming
error, but one that the compiler cannot possibly catch.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orientie objet/
                    Beratung in objektorientierter Datenverarbeitung

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

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




Author: allan_w@my-dejanews.com (Allan W)
Date: 23 Jan 2003 05:42:16 -0500
Raw View
kanze@gabi-soft.de (James Kanze) wrote
> Interesting point.  So given the following:
>
>     #include <iosfwd>
>
>     struct MyClass ;
>     extern std::ostream& operator<<( std::ostream&, MyClass const& ) ;
>
>     void
>     f( ostream& dest, MyClass const& obj )
>     {
>         dest << obj ;
>     }
>
> do I get a (required) compiler error, is it undefined behavior, or ... ?
>
> Now how about:
>
>     #include <iosfwd>
>
>     struct MyClass { MyClass( const char* ) ; } ;
>     extern std::ostream& operator<<( std::ostream&, MyClass const& ) ;
>
>     void
>     f( ostream& dest )
>     {
>         dest << "Hello, world" ;
>     }
>
> Again, required diagnostic, undefined behavior, or ... ?
>
> I rather think that this is a question for comp.std.c++.  I've
> cross-posted; I'd set the follow-ups as well, but Google won't let me.

I always thought that <iosfwd> was designed to let you declare
functions which take a reference to (say) an ostream, rather than
allowing you to operate on that ostream.

So this would be legal:

    // MyClass.h
    #include <iosfwd>
    class MyClass {
       int i;
       // ...
    };
    ostream &operator<<(ostream&, const MyClass&);

But this would not be, unless we added #include <iostream>:

    // MyClass.cpp
    #include "MyClass.h"
    ostream &operator<<(ostream&out, const MyClass&c) {
        return out << i; // Error -- ostream is an incomplete class!
    }

> > Since the non member operator<< functions are required to be in the
> > ostream header along with basic_ostream class definition it shouldn't
> > be possible to use cout << anything without getting all of the std
> > operator<< functions or a compile time error.
>
> I think I agree for a correct program.  The initial example is not,
> IMHO, a correct program, because it uses << without including
> <ostream>.  I suspect, however, there there are (and will be) a lot more
> incorrect programs that we'd like.  Incorrect programs which will still
> work on most implementations.
>
> I've very curious about the meaning of my two sample programs; I rather
> suspect that as people become used to the new headers, the first example
> will become rather frequent -- don't include more than you have to,
> which means using <iosfwd> most of the time in headers.  The second case
> is, IMHO, decidedly incorrect, since the header which contains the
> desired operator overload is not included.  But I suspect that it will
> occur from time to time.  I'd like to see it be a compiler error, but I
> can't quite see how to implement it if it is, and <iosfwd> is to remain
> useful.

I think both of your examples could be illegal, without making <iosfwd>
useless.
---
[ 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.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.de (James Kanze)
Date: 21 Jan 03 07:24:46 GMT
Raw View
Graeme Prentice <gp1@paradise.net.nz> wrote in message
news:<3nlj2vo57ttfj6patnttnpdc94ui9kb1km@4ax.com>...
> On 17 Jan 2003 14:51:48 -0500, kanze@gabi-soft.de (James Kanze) wrote:

> >> From a standard-point of view, nothing like this is guraranteed to
> >>   work:

>  >> #include <iostream>
>  >> int main()
>  >> {
>  >> std::cout << "Hello world";
>  >> }

>  >Exactly.  Formally, I think it is undefined behavior, although I'm
>  >not really certain.  Practically, it might fail to compile, it might
>  >output the address of the string literal, or it might output "Hello,
>  >world".  Or maybe something else, but off hand, those are the only
>  >possibilities I can think of.

>  >In a larger program, it is worse, because you may also include some
>  >"MyClass.hh" which defines an operator<< for MyClass -- if MyClass
>  >has a constructor taking a char const*, and <iostream> doesn't
>  >define any of the << operators, you will construct a temporary
>  >MyClass and output it.

> For an expression cout << "hello"; the standard specifies that the
> members of cout have to be inspected if cout is known to be a class -
> this implies that the definition of the cout class has to be visible,
> in which case the operator<< that takes a const void* will be used
> because it's a standard conversion rather than operator( ostream&,
> const MyClass& ) which requires a user defined conversion.

Interesting point.  So given the following:

    #include <iosfwd>

    struct MyClass ;
    extern std::ostream& operator<<( std::ostream&, MyClass const& ) ;

    void
    f( ostream& dest, MyClass const& obj )
    {
        dest << obj ;
    }

do I get a (required) compiler error, is it undefined behavior, or ... ?

Now how about:

    #include <iosfwd>

    struct MyClass { MyClass( const char* ) ; } ;
    extern std::ostream& operator<<( std::ostream&, MyClass const& ) ;

    void
    f( ostream& dest )
    {
        dest << "Hello, world" ;
    }

Again, required diagnostic, undefined behavior, or ... ?

I rather think that this is a question for comp.std.c++.  I've
cross-posted; I'd set the follow-ups as well, but Google won't let me.

> Since the non member operator<< functions are required to be in the
> ostream header along with basic_ostream class definition it shouldn't
> be possible to use cout << anything without getting all of the std
> operator<< functions or a compile time error.

I think I agree for a correct program.  The initial example is not,
IMHO, a correct program, because it uses << without including
<ostream>.  I suspect, however, there there are (and will be) a lot more
incorrect programs that we'd like.  Incorrect programs which will still
work on most implementations.

I've very curious about the meaning of my two sample programs; I rather
suspect that as people become used to the new headers, the first example
will become rather frequent -- don't include more than you have to,
which means using <iosfwd> most of the time in headers.  The second case
is, IMHO, decidedly incorrect, since the header which contains the
desired operator overload is not included.  But I suspect that it will
occur from time to time.  I'd like to see it be a compiler error, but I
can't quite see how to implement it if it is, and <iosfwd> is to remain
useful.

--
James Kanze                           mailto:jkanze@caicheuvreux.com
Conseils en informatique orientie objet/
                    Beratung in objektorientierter Datenverarbeitung

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]

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