Topic: Declaring class names


Author: Gerard Weatherby <gerardw@alum.mit.edu>
Date: 1997/04/13
Raw View

A
Alexandre Oliva wrote:
-
- Ken Walter writes:
-
- > class Bar;    // should be exactly equivalent to:
- > class Foo<int>; // this cannot be harder than instantiation itself.
-
- Ok.  Now, given the above declarations, one writes:
-
- void foo(Bar& b) { /* do something */ }
-
- void foo(Foo<int>& p) { /* do something else */ }
-
- typedef Foo<int> Bar;
- Would this program be valid?  Which version of foo would badfoo
- invoke?
-
The second declaration of Bar is invalid.  How is the above example any
different from:

class Bar;
void foo(Bar &);
void foo(int);
typedef int Bar;
void badfoo() {
  Bar x;
  foo(x);
}
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Alexandre Oliva <oliva@dcc.unicamp.br>
Date: 1997/04/11
Raw View

Ken Walter writes:

> class Bar;  // should be exactly equivalent to:
> class Foo<int>; // this cannot be harder than instantiation itself.

Ok.  Now, given the above declarations, one writes:

void foo(Bar& b) { /* do something */ }

void foo(Foo<int>& p) { /* do something else */ }

typedef Foo<int> Bar;

void badfoo() {
  Bar x;
  foo(x);
}

Would this program be valid?  Which version of foo would badfoo
invoke?

How could this be handled if the different definitions of foo were
provided in different translation units, and the typedef were
provided in only one of them?


This just can't work.  You may understant a class declaration as an
instantiation of an object of class `Class', and a typedef as a
reference to another object of class `Class'.  If you declare:

class Bar;      /* Class Bar; */
class Foo<int>; /* Class Foo<int>; &/

you're creating two objects of class `Class'.  You could not later on
define that one of them is a reference to the other, by declaring:

typedef Foo<int> Bar; /* class &Bar = Foo<int>; */

--
Alexandre Oliva
mailto:oliva@dcc.unicamp.br mailto:aoliva@acm.org
Universidade Estadual de Campinas, SP, Brasil
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/03/31
Raw View
danm@ziplink.net (Dan Muller) writes:

>The real question in my mind is why the draft doesn't explicitly require
>a class template instantiation to be treated as class type for purposes
>such as this. After all, if instantiating a class template doesn't create
>a class, what *does* it create?

The draft *does* require that a class template instantiation be treated
as a class type.  You can forward declare an instantiation, e.g.

 // forward declare a class template
 template <class T> class Foo;

 // forward declare a class template instantiation
 class Foo<int>;

 // use the forward declared class template instantiation
 Foo<int> *p;
 typedef Foo<int> Bar;
 Bar *p;

What C++ does not allow is treating a _typedef_ that names a
template class instantiation as a class type:

 class Bar; // not allowed

Note there is a diference between a typedef that _names_ a type
and the type itself.

The reasons why this is not allowed, namely difficulty of specification
(e.g. problems with overloading and the need to make non-backwards-
compatible changes to the linkage rules) and difficulty of implementation
(e.g. problems with name mangling and separate compilation),
have already been explained on other messages in this thread.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Stephen.Clamage@Eng.Sun.COM (Steve Clamage)
Date: 1997/03/31
Raw View
In article 9ek@ds2.acs.ucalgary.ca, norman@enel.ucalgary.ca (Stephen Norman) writes:
>
>   #include <iosfwd>
>   using std::ostream;
>
>   class X;
>   ostream& print(ostream& os, const X& the_x);
>
>That way you can declare `print' without dragging all of <iostream> into
>the translation unit. (Somebody please correct me if I have misconstrued
>the purpose of <iosfwd>.)
>
>I wonder why there is no standard header called <stringfwd> to solve
>the same sort of problems with the typedef for string?

Whether it is expensive to include complete iostream or string (or
whatever) headers in a program is considered a "quality-of-implementation"
issue, not a standards issue. Popular implementations exist which have
little compile-time overhead in including full headers, even multiple
times. (And I don't mean by using non-standard extensions like
"pragma once". Even g++, which used to require that extension, no longer
requires it to get efficient compile-time behavior.)

The <iosfwd> was created to achieve some (imperfect) level of backwards
compatibility. The other standard library classes are new, and no backwards-compatibility issue exists.

To use a feature of the standard library, you include its associated
header.

---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/01
Raw View
danm@ziplink.net (Dan Muller) writes:

|>  The real question in my mind is why the draft doesn't explicitly require
|>  a class template instantiation to be treated as class type for purposes
|>  such as this. After all, if instantiating a class template doesn't create
|>  a class, what *does* it create?

A class template instantiation IS a class.  But a name defined by a
typedef isn't a class.

The problem is name equivalence: there is no doubt that basic_string<
char , ... > is the name of a class.  The typedef of string, however,
does NOT make string the name of a class; it makes it an alias for the
name of a class.

In order for name equivalence to work, it is necessary for the compiler
to be able to use the actual name of the class whenever it sees the
alias.  Thus: the symbol "string" MUST be defined by means of a typedef
(which tells the compiler to use the name basic_string<...> whenever it
sees "string"), not by a forward declaration of the type "class string"
(which tells the compiler that "string" is the name of a class, so use
it).

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: icedancer@antispam.ibm.net (Ken Walter)
Date: 1997/04/01
Raw View
In message <5ho105$car@mulga.cs.mu.OZ.AU> - fjh@mundook.cs.mu.OZ.AU (Fergus
Henderson)31 Mar 1997 14:05:41 PST writes:
[...]
 :>
 :>The draft *does* require that a class template instantiation be treated
 :>as a class type.  You can forward declare an instantiation, e.g.
 :>
 :> // forward declare a class template
 :> template <class T> class Foo;
 :>
 :> // forward declare a class template instantiation
 :> class Foo<int>;
 :>
 :> // use the forward declared class template instantiation
 :> Foo<int> *p;
 :> typedef Foo<int> Bar;
 :> Bar *p;
 :>
 :>What C++ does not allow is treating a _typedef_ that names a
 :>template class instantiation as a class type:
 :>
 :> class Bar; // not allowed
 :>
 :>Note there is a diference between a typedef that _names_ a type
 :>and the type itself.
 :>
 :>The reasons why this is not allowed, namely difficulty of specification
 :>(e.g. problems with overloading and the need to make non-backwards-
 :>compatible changes to the linkage rules) and difficulty of implementation
 :>(e.g. problems with name mangling and separate compilation),
 :>have already been explained on other messages in this thread.

I don't see it.

class Bar;  // should be exactly equivalent to:
class Foo<int>; // this cannot be harder than instantiation itself.

A typedef is nothing more than a specialized form of a macro?

Ken Walter     (Remove antispam. from address)
All the above is hearsay and the opinion of no one in particular.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/04/01
Raw View
icedancer@antispam.ibm.net (Ken Walter) writes:

>fjh@cs.mu.OZ.AU (Fergus Henderson) writes:
>[...]
> :>The reasons why this is not allowed, namely difficulty of specification
> :>(e.g. problems with overloading and the need to make non-backwards-
> :>compatible changes to the linkage rules) and difficulty of implementation
> :>(e.g. problems with name mangling and separate compilation),
> :>have already been explained on other messages in this thread.
>
>I don't see it.

<sigh>
Which bit don't you see?

>class Bar;  // should be exactly equivalent to:
>class Foo<int>; // this cannot be harder than instantiation itself.

Templates are a red herring here.
The issue is just about typedefs and forward declarations.

>A typedef is nothing more than a specialized form of a macro?

Yes, roughly speaking -- but you can't forward-declare macros either!

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: danm@ziplink.net (Dan Muller)
Date: 1997/04/01
Raw View
[This followup was posted to comp.std.c++ and a copy was sent to the
cited author.]

In article <5ho105$car@mulga.cs.mu.OZ.AU>, fjh@mundook.cs.mu.OZ.AU
says...
> danm@ziplink.net (Dan Muller) writes:
>
> >The real question in my mind is why the draft doesn't explicitly require
> >a class template instantiation to be treated as class type for purposes
> >such as this. After all, if instantiating a class template doesn't create
> >a class, what *does* it create?
>
> The draft *does* require that a class template instantiation be treated
> as a class type.  You can forward declare an instantiation, e.g.
>
>  // forward declare a class template
>  template <class T> class Foo;
>
>  // forward declare a class template instantiation
>  class Foo<int>;
>
>  // use the forward declared class template instantiation
>  Foo<int> *p;
>  typedef Foo<int> Bar;
>  Bar *p;
>
> What C++ does not allow is treating a _typedef_ that names a
> template class instantiation as a class type:
>
>  class Bar; // not allowed

>
> Note there is a diference between a typedef that _names_ a type
> and the type itself.

OK, I finally got this. There was something fundamental that I was
misunderstanding, illustrated as follows:

class C2; // Forward declaration of C2

// ... make some references to C2 here ...

// And then later...
class C1 {};

typedef C1 C2; // Error

I thought that this typedef would succeed if C1 were a class, but not if
you replaced C1 with a template instantiation. In fact, even if C1 is a
class, this is not allowed, because a typedef name can't be used after a
"class" prefix. I didn't quite get this before.

> The reasons why this is not allowed, namely difficulty of specification
> (e.g. problems with overloading and the need to make non-backwards-
> compatible changes to the linkage rules) and difficulty of implementation
> (e.g. problems with name mangling and separate compilation),
> have already been explained on other messages in this thread.

And now, magically, I understand the relevance of those explanations,
and how the standard addresses these concerns. <g>

Thanks for clarifying!

--
Dan Muller   danm@ziplink.net
http://www.ziplink.net/~danm
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/01
Raw View
danm@ziplink.net (Dan Muller) writes:

|>  In article <vw9u3lw2ha7.fsf@haggard.gg.caltech.edu>,
|>  presto@haggard.gg.caltech.edu says...
|>  > In article <3338C7F0.148B@netcom.com> Scott Meyers <smeyers@netcom.com> writes:
|>  > > Isn't there some way in C++ to say "this is the name of some type,
|>  > > but I don't want to commit at this point to whether it's a struct, a
|>  > > class, an enum, a template instantiation, or a typedef."
|>  >
|>  > If that object were known to be a class, then the forward declaration
|>  > would work.  This may be a reason to avoid the typedef-to-template
|>  > pattern that is common in the STL.
|>  >
|>  >  (1) typedef basic_string<char> string;
|>  >  (2) class string : public basic_string<char> { /* overhead funcs */ };
|>  >
|>  <snip>
|>  > Opinions?  Does it sound like a good design rule to make publicly
|>  > accessed objects be classes unless there's a good reason not to?
|>
|>  Sounds like a good idea to me.
|>
|>  IMO, even better would be if the language treated instantiations of class
|>  templates as being of type class type, so that this forward declaration
|>  would work. From what I can tell by perusing the draft standard (but I'm
|>  no expert on it), the compiler behavior in this case is probably correct,
|>  but I think there's a certain amount of ambiguity around this. Perhaps
|>  it's an oversight, but OTOH perhaps there's a good reason for it.
|>
|>  In another posting in this thread, someone seemed to be alluding
|>  potential problems with generating proper function signatures for
|>  functions that reference incompletely specified types. But it seems to me
|>  that this problem exists whether the typedef eventually resolves to a
|>  true class or to an instantiated class template - in either case, the
|>  "true" name of the referenced type is different from that given in the
|>  forward declaration.

Which is why you cannot typedef to an undefined type.  A typedef must
eventually resolve in a real type name, not an alias.  (I'm using type
name in an extended sense here: char* or basic_string< char ... > are
type names, even if they aren't written as one word.)  Thus, for
example, "typedef basic_string< ... > string" is only legal if the
compiler has already seen a declaration estabilishing basic_string as a
template.

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/01
Raw View
smeyers@teleport.com (Scott Meyers) writes:

|>  In article <rf5g1xgjntu.fsf@vx.cit.alcatel.fr>,
|>  James Kanze  <james-albert.kanze@vx.cit.alcatel.fr> wrote:
|>  | What you are asking is to be able to write things like:
|>  |
|>  |  extern void f( string& ) ;
|>  |  void g( string& arg ) { f( arg ) ; }
|>  |
|>  | in a module, without ever fully defining string.  However, in order to
|>  | implement typesafe linkage (and in some cases, correct function
|>  | overloading), it is necessary for the compiler to at least know the full
|>  | "type" of string.
|>
|>  I was under the impression that the standard dealt with neither typesafe
|>  linkage nor name mangling (which you referred to later).  Overloading
|>  resolution is a problem, however, I see that now.  Sigh.

The standard doesn't deal with typesafe linkage or name mangling as
such.  The authors, however, are concerned that the final standard is
implementable; name mangling is the classical implementation solution
for overloaded functions, and typesafe linkage is its correlary.  (In a
certain sense, some form of typesafe linkage is necessary for function
overloading to work.)

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/04/01
Raw View
James Kanze <james-albert.kanze@vx.cit.alcatel.fr> writes:

>A class template instantiation IS a class.  But a name defined by a
>typedef isn't a class.

... and hence can't be forward declared as a class.

>The problem is name equivalence:

It's not that simple.  There is at least one language that has name
equivalence of types, has an equivalent to typedefs, and allows the
types to be forward declared, and allows types declared in this manner
to be defined using typedefs.

The language I'm thinking of is Mercury.  In Mercury, the issue of name
equivalence is handled quite simply: a typedef name is equivalent
to the type that it names if and only if the typedef is in scope.  The
sort of ODR problems you have in C++ don't arise in Mercury because
Mercury has a module system in which there really is only one
definition of each entity, rather than multiple definitions in
different translation units which may or may not be equivalent.

There are a number of problems which make this thing unsolvable
in C++.  But blaming name equivalence alone is over-simplifying
things, IMHO.  If I had to narrow it down to one or two causes,
I would blame implicit conversions and the lack of a proper module
system.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Stephen.Clamage@eng.sun.com (Steve Clamage)
Date: 1997/04/01
Raw View
In article 871@mulga.cs.mu.OZ.AU, fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) writes:
>icedancer@antispam.ibm.net (Ken Walter) writes:
>>A typedef is nothing more than a specialized form of a macro?
>
>Yes, roughly speaking ...

I don't agree.

Macros operate on the text of the source code before any syntax or
semantic analysis occurs. Macros do not obey scope rules. The C++ type
system is unknown to macros.

Typedefs do not come into play until all macros are fully evaluated.
Typedefs obey all scope rules, and are part of the C++ type system.

Even these simple examples show some of the differences:

#define INT1 int  // these lines are
typedef int INT2; // not equivalent

const INT1 * p1; // non-const pointer to const int
const INT2 * p2; // const pointer to non-const int (non-intuitive result)

void foo()
{
 #undef INT1 // required to make the next line valid
 #define INT1 char // error without the #undef
 typedef char INT2; // ok
 ...
}
INT2 i2; // type int  -- reverts to outer scope definition
INT1 i1; // type char -- retains last definition regardless of scope

I think these example also show why you want to avoid using macros.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: norman@enel.ucalgary.ca (Stephen Norman)
Date: 1997/04/01
Raw View
In article <199703311825.KAA12551@taumet.eng.sun.com>,
Steve Clamage <Stephen.Clamage@Eng.Sun.COM> wrote:
>The <iosfwd> was created to achieve some (imperfect) level of backwards
>compatibility. The other standard library classes are new, and no
>backwards-compatibility issue exists.
>
>To use a feature of the standard library, you include its associated
>header.

What is the backwards-compatibility issue addressed by <iosfwd>?
It can't be the one I was thinking of, because I suggested in my
earlier post that this:

  // Old code.
  class ostream;
  class X;
  ostream& print(ostream&, const X&);

could be replaced with this:

  // Standard-compliant, I hope.
  #include <iosfwd>
  using std::ostream;
  class X;
  ostream& print(ostream&, const X&);

But if my implementation processes #includes of standard library headers
without significant overhead, I might as well just write this:

  #include <iostream>  // Who needs <iosfwd>?
  using std::ostream;
  class X;
  ostream& print(ostream&, const X&);

Is there some reason other than reducing compilation time for the
existence of <iosfwd>?

--Steve Norman
  U of Calgary Dept of Electrical & Computer Engineering
  norman@enel.ucalgary.ca
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Christian Millour <chris161@club-internet.fr>
Date: 1997/04/02
Raw View
Stephen Norman wrote:
>   // Standard-compliant, I hope.
>   #include <iosfwd>
>   using std::ostream;
>   class X;
>   ostream& print(ostream&, const X&);
>
> But if my implementation processes #includes of standard library headers
> without significant overhead, I might as well just write this:
>
>   #include <iostream>  // Who needs <iosfwd>?
>   using std::ostream;
>   class X;
>   ostream& print(ostream&, const X&);
>
> Is there some reason other than reducing compilation time for the
> existence of <iosfwd>?

by my understanding of CD2 (27.3, verse 1) the purpose of
<iostream> is to declare cin, cout, cerr, clog and their
wide-char counterparts.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Oleg Zabluda <zabluda@math.psu.edu>
Date: 1997/04/02
Raw View
Steve Clamage <Stephen.Clamage@eng.sun.com> wrote:
: #define INT1 int  // these lines are
: typedef int INT2; // not equivalent

: const INT1 * p1; // non-const pointer to const int
: const INT2 * p2; // const pointer to non-const int (non-intuitive result)

: I think these example also show why you want to avoid using macros.

Actually, this seems to show why you want to avoid typedefs and prefer
macros. I've already learned from some other posts, that one should
write 'INT2 const * p2'. This is crazy. Is it that hard to fix?
What if a user doesn't even know that INT2 is a typedef, not a real
type?

Oleg.
--
Life is a sexually transmitted, 100% lethal disease.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Stephen.Clamage@Eng.Sun.COM (Steve Clamage)
Date: 1997/04/02
Raw View
In article LAA14005@taumet.eng.sun.com, I foolishly wrote:
>
>#define INT1 int  // these lines are
>typedef int INT2; // not equivalent
>
>const INT1 * p1; // non-const pointer to const int
>const INT2 * p2; // const pointer to non-const int (non-intuitive result)

Abhishek Chauhan was the first, and probably not the last, to point
out that I made a mistake here. In this example, p1 and p2 do indeed
have the same type.

Here is the example as I should have written it, followed by a
discussion of what I meant by "counter-intuitive":

#define INT1 int*
typedef int* INT2;

const INT1* p1; // const int** == pointer to (pointer to (const int))
const INT2* p2; // int* const* == pointer to (const (pointer to int))

People sometimes find the resulting type of p2 non-intuitive because
they expect the typedef to behave like the macro. It doesn't, and
that is why I don't like to say that typedefs are like macros:
they are not. If you think of a typedef as creating a type name,
which is what it does, you won't make that mistake.

If T is a type name, then
 const T *
and
 T const *
mean the same thing: "pointer to const T". Replace T with INT2 and
you have the above example. Then replace type INT2 with type int*
(which is not the same as replacing text before parsing the type
declaration) and you get the translation in the comment.

Yes, it seems unnecessarily confusing, but that is the heritage
of the C declaration syntax.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/04/03
Raw View
Stephen.Clamage@eng.sun.com (Steve Clamage) writes:

|>  Even these simple examples show some of the differences:
|>
|>  #define INT1 int  // these lines are
|>  typedef int INT2; // not equivalent
|>
|>  const INT1 * p1; // non-const pointer to const int
|>  const INT2 * p2; // const pointer to non-const int (non-intuitive result)

Now I'm confused.  How can the pointer be const instead of the int?  The
const is obviously part of the declaration specifier, whereas the
pointer is part of the declarator.

When the type in question is just a simple name, the typedef and the
macro DO have pretty much the same effects (except for scoping).  Where
the difference comes into play is when the typedef has modifiers in the
declarator, e.g.:

 #define PTRI1 int*
 typedef int* PTRI2 ;

 const PTRI1 p1 ;     // non-const pointer to const int
 const PTRI2 p2 ;     // const pointer to non-const int

Written this way, the results may be non-intuitive, but written using
the convention of always putting const behind what it modifies:

 PTRI1 const p1 ;    // const pointer to non-const int
 PTRI2 const p1 ;    // const pointer to non-const int

Which is what one would expect in both cases (IMHO).

BTW, one point you didn't mention is that there are a lot of typedef's
which simply cannot be simulated with a #define.  How would you write a
#define for an array, a pointer to function or a pointer to member.  And
it is precisely for complex definitions like those involving pointers to
members that you most want a typedef.

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1997/04/06
Raw View
Dan Muller wrote:
>
> In article <vw9u3lw2ha7.fsf@haggard.gg.caltech.edu>,
> presto@haggard.gg.caltech.edu says...
> > In article <3338C7F0.148B@netcom.com> Scott Meyers <smeyers@netcom.com> writes:
> > > Isn't there some way in C++ to say "this is the name of some type,
> > > but I don't want to commit at this point to whether it's a struct, a
> > > class, an enum, a template instantiation, or a typedef."

> IMO, even better would be if the language treated instantiations of class
> templates as being of type class type,

But they are classes.

> so that this forward declaration
> would work. From what I can tell by perusing the draft standard (but I'm
> no expert on it), the compiler behavior in this case is probably correct,
> but I think there's a certain amount of ambiguity around this. Perhaps
> it's an oversight, but OTOH perhaps there's a good reason for it.
>
> In another posting in this thread, someone seemed to be alluding
> potential problems with generating proper function signatures for
> functions that reference incompletely specified types. But it seems to me
> that this problem exists whether the typedef eventually resolves to a
> true class or to an instantiated class template - in either case, the
> "true" name of the referenced type is different from that given in the
> forward declaration.

No: typedef don't have linkage; the solution could perhaps be to
have 'extern typedef'.

template <typename T> class basic_string; // (1)
typedef basic_string<char> string;

void    foo (string);

so foo has type void (basic_string<char>).

typedef basic_string<char> String;

void    bar (String);

so bar and foo have the same type. If (1) is ommited
how do you know ? typedef are macros: they don't create
a type and have no linkage (but, unlike macro, they
behave properly like others names in the language: they
hide/nest/obey visibillity rules).

What about:

extern typename string;

In bar.cp:

void    foo (string*);

void    bar (string* r)
{
    foo (r);
}

In foo.cp:

template <typename T>
class basic_string
{ // ...
};

void    foo (basic_string<char>*);

extern typedef basic_string<char> string;

Then two functions names void foo (basic_string<char>*) and
void foo (string*) have to be reconnised by the linker has
the same function using the global extern typedef database.

--

Valentin Bonnard
mailto:bonnardv@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/03/27
Raw View
Scott Meyers <smeyers@netcom.com> writes:

>Isn't there some way in C++ to say "this is the
>name of some type, but I don't want to commit at this point to whether
>it's a struct, a class, an enum, a template instantiation, or a
>typedef."

No, there isn't.

It would be very difficult to implement such a construct, or even to
just specify its behaviour.  Consider the following example:

 // translation unit 1:
 typedef char Foo;

 // translation unit 2:
 typedef void Foo;

 // translation unit 3:
 #include <iostream>
 using std;

 forward_declare_type Foo; // the hypothetical construct
 extern Foo * foo();

 int main() {
  cout << foo() << endl;
 }

 // translation unit 4:
 #if BLAH
 void *foo() { return "hello world"; }
 #else
 char *foo() { return "hello world"; }
 #endif

What should the correct behaviour here be?  Which `Foo' should the
declaration in translation unit 3 bind to?  How can the compiler know
which version of `operator <<' to call in translation unit 3?

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Jonathan Fry <jon@spss.com>
Date: 1997/03/28
Raw View
Fergus Henderson wrote:
 >
 > Scott Meyers <smeyers@netcom.com> writes:
 >
 > >Isn't there some way in C++ to say "this is the
 > >name of some type, but I don't want to commit at this point to whether
 > >it's a struct, a class, an enum, a template instantiation, or a
 > >typedef."
 >
 > No, there isn't.
 >
 > It would be very difficult to implement such a construct, or even to
 > just specify its behaviour.  Consider the following example:
 >
 >         // translation unit 1:
 >         typedef char Foo;
 >
 >         // translation unit 2:
 >         typedef void Foo;
 >
 >         // translation unit 3:
 >         #include <iostream>
 >         using std;
 >
 >         forward_declare_type Foo;       // the hypothetical construct
 >         extern Foo * foo();
 >
 >         int main() {
 >                 cout << foo() << endl;
 >         }
 >
 >         // translation unit 4:
 >         #if BLAH
 >         void *foo() { return "hello world"; }
 >         #else
 >         char *foo() { return "hello world"; }
 >         #endif
 >
 > What should the correct behaviour here be?  Which `Foo' should the
 > declaration in translation unit 3 bind to?  How can the compiler know
 > which version of `operator <<' to call in translation unit 3?
[snip]

The behavior I would like, and I think Scott Meyers would like as well,
is exactly the same as if

 class Foo;

had appeared in translation unit 3 instead of

 forward_declared_type Foo;

The only difference appears in translation units in which the
declaration of Foo is completed.  An incomplete class declaration can be
completed only by a class or struct statement.  I want to be able to
complete a forward declaration with a typedef or enum statement as well.
--
--------------------
Jonathan Fry
SPSS Inc.
jon@spss.com
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: James Kanze <james-albert.kanze@vx.cit.alcatel.fr>
Date: 1997/03/28
Raw View
Scott Meyers <smeyers@netcom.com> writes:

|>  Suppose I'd like to declare this simple function:
|>
|>    void f(const string& s);
|>
|>  To do that, I have to declare class string.  I'd like to do it like
|>  this,
|>
|>    class string;
|>
|>  but of course string isn't really a class, it's a typedef for an
|>  instantiation of the basic_string template:
|>
|>    typedef basic_string<char> string;
|>
|>  So in order to declare string, I have to declare basic_string:
|>
|>     template<class charT,
|>              class traits = char_traits<charT>,
|>              class Allocator = allocator<charT> >
|>       class basic_string;
|>
|>  But that requires that I declare char_traits and allocator.  The end
|>  result is that what I'd like to write like this:
|>
|>    class string;
|>    void f(const string& s);
|>
|>  I must instead write like this:
|>
|>     template<class charT> struct char_traits;
|>     template <class T> class allocator;
|>     template<class charT, class traits = char_traits<charT>,
|>              class Allocator = allocator<charT> > class basic_string;
|>     typedef basic_string<char> string;
|>     void f(const string& s);
|>
|>  Is that really true?

Yes.

Note that it means that a forward declaration requires knowledge of the
internals of the "class".

|>  Isn't there some way in C++ to say "this is the
|>  name of some type, but I don't want to commit at this point to whether
|>  it's a struct, a class, an enum, a template instantiation, or a
|>  typedef."  I seem to recall that typename serves this purpose, but I
|>  don't know how to apply it in this context.

It can't be done.  Technically.

What you are asking is to be able to write things like:

 extern void f( string& ) ;
 void g( string& arg ) { f( arg ) ; }

in a module, without ever fully defining string.  However, in order to
implement typesafe linkage (and in some cases, correct function
overloading), it is necessary for the compiler to at least know the full
"type" of string.

If string is a class, then its full type is "class string".  However, in
fact, we know that the full type of string is "basic_string< char ,
...>", which is not the same thing.  If the compiler implements type
safe linkage and overloading using a form of name mangling (a frequent
case), how is it to know how to mangle the names in the above example.

--
James Kanze      home:     kanze@gabi-soft.fr        +33 (0)1 39 55 85 62
                 office:   kanze@vx.cit.alcatel.fr   +33 (0)1 69 63 14 54
GABI Software, Sarl., 22 rue Jacques-Lemercier, F-78000 Versailles France
     -- Conseils en informatique industrielle --
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: presto@haggard.gg.caltech.edu (Preston Pfarner)
Date: 1997/03/28
Raw View
In article <3338C7F0.148B@netcom.com> Scott Meyers <smeyers@netcom.com> writes:
> Isn't there some way in C++ to say "this is the name of some type,
> but I don't want to commit at this point to whether it's a struct, a
> class, an enum, a template instantiation, or a typedef."

If that object were known to be a class, then the forward declaration
would work.  This may be a reason to avoid the typedef-to-template
pattern that is common in the STL.

 (1) typedef basic_string<char> string;
 (2) class string : public basic_string<char> { /* overhead funcs */ };

(1) is the current standard form, but if the second form were used,
forward declaration would be allowed.  It also strikes me that (2)
is nicer for aesthetic encapsulation aspects.  Of course, (2) has
the standard problems of inheriting a concrete class from another
concrete class, but that might be preferable to including the
full definition of all of string's dependencies.

There's also the option of delegation combined with containment or
private inheritence, but maintenance of delegation is often
prohibitive.

While this pattern probably doesn't help with the STL, which seems
quite fixed at this point, it might be useful for user-defined
libraries.  This would add some overhead, effectively defeating any
inlining in the base type.

Opinions?  Does it sound like a good design rule to make publicly
accessed objects be classes unless there's a good reason not to?


--
   Preston Pfarner
   mailto:presto@gg.caltech.edu
   http://www.gg.caltech.edu/~presto/
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Michael R Cook <michael_cook%erawan@cognex.com>
Date: 1997/03/28
Raw View
>>>>> "FH" == Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> writes:

 FH>  forward_declare_type Foo; // the hypothetical construct
 FH>  extern Foo * foo();

How about:

  extern typename Foo * foo();

 FH>  int main() {
 FH>   cout << foo() << endl;
 FH>  }

 FH> What should the correct behaviour here be?

The compiler could reject the code on the basis that `Foo' is incomplete.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: norman@enel.ucalgary.ca (Stephen Norman)
Date: 1997/03/28
Raw View
In article <3338C7F0.148B@netcom.com>,
Scott Meyers  <smeyers@netcom.com> wrote:
> [...]
>The end
>result is that what I'd like to write like this:
>
>  class string;
>  void f(const string& s);
>
>I must instead write like this:
>
>   template<class charT> struct char_traits;
>   template <class T> class allocator;
>   template<class charT, class traits = char_traits<charT>,
>            class Allocator = allocator<charT> > class basic_string;
>   typedef basic_string<char> string;
>   void f(const string& s);
>
>Is that really true?  Isn't there some way in C++ to say "this is the
>name of some type, but I don't want to commit at this point to whether
>it's a struct, a class, an enum, a template instantiation, or a
>typedef."

I don't know what the answer is, but it seems to me that the standard
header file <iosfwd> has been created to deal with this kind of problem in
the case of types related to I/O streams.  Fragments like this (which
I imagine are ubiquitous in existing code):

   class ostream;
   class X;
   ostream& print(ostream& os, const X& the_x);

will no longer be allowed, and should be replaced with

   #include <iosfwd>
   using std::ostream;

   class X;
   ostream& print(ostream& os, const X& the_x);

That way you can declare `print' without dragging all of <iostream> into
the translation unit. (Somebody please correct me if I have misconstrued
the purpose of <iosfwd>.)

I wonder why there is no standard header called <stringfwd> to solve
the same sort of problems with the typedef for string?

--Steve Norman
  U of Calgary Dept of Electrical & Computer Engineering
  norman@enel.ucalgary.ca
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: "Larry Brasfield" <SpamGuard_larrybr@microsoft.com>
Date: 1997/03/28
Raw View
Dan Muller <danm@ziplink.net> wrote in article
<MPG.da39db8a62920369896cb@news.ziplink.net>...
[prior discussion cut]
> This makes me wonder if the following would be a wiser way to define a
> synonym for a template instantiation:
>
> template<typename T> class a_template {};
> class C : public a_template<char> {};
>
> This would be almost equivalent to "typedef a_template<char> C;", but
> doesn't suffer from the forward declaration problem.
>
> Am I interpreting the standard correctly?

This would be a neat work-around, except for the fact that
it cuts all the constructors out.  The "typedef ... C;" allows
C to have the constructors defined for "...", whereas once
you inherit from "...", C only has a default constructor.

This reminds me again of how nice it would be to have a
way to forward all the constructors from a single base.
Given class D : public B { ... };, I want to avoid having to
write
  D(blah) : B(blah) {}
  D(hooey, looey) : B(hooey, looey) {}
  etc.

Maybe we'll see it for C++++

--
-- Larry Brasfield
-- The aforementioned views are mine alone and are not
-- to be construed as representing my employer's views.
-- (For an e-mail reply, remove SpamGuard_.)
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: danm@ziplink.net (Dan Muller)
Date: 1997/03/28
Raw View
In article <vw9u3lw2ha7.fsf@haggard.gg.caltech.edu>,
presto@haggard.gg.caltech.edu says...
> In article <3338C7F0.148B@netcom.com> Scott Meyers <smeyers@netcom.com> writes:
> > Isn't there some way in C++ to say "this is the name of some type,
> > but I don't want to commit at this point to whether it's a struct, a
> > class, an enum, a template instantiation, or a typedef."
>
> If that object were known to be a class, then the forward declaration
> would work.  This may be a reason to avoid the typedef-to-template
> pattern that is common in the STL.
>
>  (1) typedef basic_string<char> string;
>  (2) class string : public basic_string<char> { /* overhead funcs */ };
>
<snip>
> Opinions?  Does it sound like a good design rule to make publicly
> accessed objects be classes unless there's a good reason not to?

Sounds like a good idea to me.

IMO, even better would be if the language treated instantiations of class
templates as being of type class type, so that this forward declaration
would work. From what I can tell by perusing the draft standard (but I'm
no expert on it), the compiler behavior in this case is probably correct,
but I think there's a certain amount of ambiguity around this. Perhaps
it's an oversight, but OTOH perhaps there's a good reason for it.

In another posting in this thread, someone seemed to be alluding
potential problems with generating proper function signatures for
functions that reference incompletely specified types. But it seems to me
that this problem exists whether the typedef eventually resolves to a
true class or to an instantiated class template - in either case, the
"true" name of the referenced type is different from that given in the
forward declaration.

> ---
> [ 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         ]
> [ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
> [ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
> [ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]
>

--
Dan Muller   danm@ziplink.net
http://www.ziplink.net/~danm
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/03/28
Raw View
smeyers@teleport.com (Scott Meyers) writes:

>Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> wrote:
>| What should the correct behaviour here be?  Which `Foo' should the
>| declaration in translation unit 3 bind to?  How can the compiler know
>| which version of `operator <<' to call in translation unit 3?
>
>ODR violation, results are undefined.

According to the current rules, it is not an ODR violation, because
typedefs have no linkage, so the two `Foos' are different entities,
not conflicting definitions of the same entity.

So if you want a `forward_declare_type' construct, then you need to
change the rules for linkage of typedefs.  When should a typedef
have external linkage?  (Be careful that your answer doesn't break
existing programs.)

Furthermore, there is still another problem: if you leave out
translation unit 2 (`typedef void Foo') from my original example, then
there is no ODR violation.  But the compiler can't determine which
overloaded function it should call in translation unit 3 without
looking at the other translation units; solving this would require
substantial revision to C++'s model of separate compilation.

In summary:
I agree that it is a pity that you can't forward declare
types in this manner in C++.  Future languages should be
designed to allow this sort of thing.  However, retro-fitting
it into C++ would be very difficult.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: comeau@panix.com (Greg Comeau)
Date: 1997/03/28
Raw View
In article <3338C7F0.148B@netcom.com> Scott Meyers <smeyers@netcom.com> writes:
>The end result is that what I'd like to write like this:
>
>  class string;
>  void f(const string& s);
>
>I must instead write like this:
>
>   template<class charT> struct char_traits;
>   template <class T> class allocator;
>   template<class charT, class traits = char_traits<charT>,
>            class Allocator = allocator<charT> > class basic_string;
>   typedef basic_string<char> string;
>   void f(const string& s);
>
>Is that really true?

I hate this to death, but yes.

>Isn't there some way in C++ to say "this is the
>name of some type, but I don't want to commit at this point to whether
>it's a struct, a class, an enum, a template instantiation, or a
>typedef."

No, but you can do this: <string>.  Yes, I know.
Ok: you can do this: <mystring.h>. Yes, I know.  Perhaps even worse.

>  I seem to recall that typename serves this purpose, but I
>don't know how to apply it in this context.

It "serves that purpose" in a different way and place, so it doesn't apply.

>BTW, I'm interested in the general case of forward-declaring a type, not
>just the particular case of string.  I only chose string because it's
>both familiar enough and gruesome enough to, I hope, make the problem
>clear.

It's clear.  I can remember my groans when it first dawned on me that
this is true of say some stuff in iostreams too.  This is one that's
nobody's fault.

- Greg
--
       Comeau Computing, 91-34 120th Street, Richmond Hill, NY, 11418-3214
               Producers of Comeau C++ 4.0 front-end pre-release
****WEB: http://www.comeaucomputing.com / Voice:718-945-0009 / Fax:718-441-2310
 Here:comeau@comeaucomputing.com / BIX:comeau or comeau@bix.com / CIS:72331,3421
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: smeyers@teleport.com (Scott Meyers)
Date: 1997/03/29
Raw View
In article <5hdai5$que@mulga.cs.mu.OZ.AU>,
Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> wrote:
| What should the correct behaviour here be?  Which `Foo' should the
| declaration in translation unit 3 bind to?  How can the compiler know
| which version of `operator <<' to call in translation unit 3?

ODR violation, results are undefined.

Scott

--
Scott Meyers, Ph.D.                  Voice: 503/638-6028
C++ Consulting and Training          Fax:   503/638-6614
Author of "Effective C++"            Email: smeyers@netcom.com
  and "More Effective C++"           WWW:   http://www.teleport.com/~smeyers
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/03/29
Raw View
Jonathan Fry <jon@spss.com> writes:

 >Fergus Henderson wrote:
 >
 > > It would be very difficult to implement such a construct, or even to
 > > just specify its behaviour.  Consider the following example:
 > >
 > >         // translation unit 1:
 > >         typedef char Foo;
 > >
 > >         // translation unit 2:
 > >         typedef void Foo;
 > >
 > >         // translation unit 3:
 > >         #include <iostream>
 > >         using std;
 > >
 > >         forward_declare_type Foo;       // the hypothetical construct
 > >         extern Foo * foo();
 > >
 > >         int main() {
 > >                 cout << foo() << endl;
 > >         }
 > >
 > >         // translation unit 4:
 > >         #if BLAH
 > >         void *foo() { return "hello world"; }
 > >         #else
 > >         char *foo() { return "hello world"; }
 > >         #endif
 > >
 > > What should the correct behaviour here be?  Which `Foo' should the
 > > declaration in translation unit 3 bind to?  How can the compiler know
 > > which version of `operator <<' to call in translation unit 3?
 >[snip]
 >
 >The behavior I would like, and I think Scott Meyers would like as well,
 >is exactly the same as if
 >
 > class Foo;
 >
 >had appeared in translation unit 3 instead of
 >
 > forward_declared_type Foo;

But that is awful, because the resulting behaviour (assuming that `BLAH'
is not defined) is that it calls the _wrong_ version of the overloaded
operator.  Specifically, the statement

 cout << foo() << endl;

in translation unit 3 will print the _address_ of the string, rather
than printing the string, even though foo() is defined as

 char *foo() { return "hello world"; }

in translation unit 4.

Do you _really_ want that??

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: Marcelo Cantos <marcelo@mds.rmit.edu.au>
Date: 1997/03/30
Raw View
Michael R Cook <michael_cook%erawan@cognex.com> writes:

>
> >>>>> "FH" == Fergus Henderson <fjh@mundook.cs.mu.OZ.AU> writes:
>
>  FH>  forward_declare_type Foo; // the hypothetical construct
>  FH>  extern Foo * foo();
>
> How about:
>
>   extern typename Foo * foo();
>
>  FH>  int main() {
>  FH>   cout << foo() << endl;
>  FH>  }
>
>  FH> What should the correct behaviour here be?
>
> The compiler could reject the code on the basis that `Foo' is incomplete.

Not as far as I know.  The << operator is only operating on a pointer
and has no need to know the contents or layout of the object.  The
following:

  cout << *foo() << endl;

would still be legal, but the corresponding operator<<(...Foo&) would
fail.


--
______________________________________________________________________
Marcelo Cantos, Research Assistant      __/_   marcelo@mds.rmit.edu.au
Multimedia Database Systems Group, RMIT  /       _  Tel 61-3-9282-2497
723 Swanston St, Carlton VIC 3053    Aus/ralia ><_> Fax 61-3-9282-2490
Acknowledgements: errors - me; wisdom - God; funding - RMIT
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: smeyers@teleport.com (Scott Meyers)
Date: 1997/03/30
Raw View
In article <rf5g1xgjntu.fsf@vx.cit.alcatel.fr>,
James Kanze  <james-albert.kanze@vx.cit.alcatel.fr> wrote:
| What you are asking is to be able to write things like:
|
|  extern void f( string& ) ;
|  void g( string& arg ) { f( arg ) ; }
|
| in a module, without ever fully defining string.  However, in order to
| implement typesafe linkage (and in some cases, correct function
| overloading), it is necessary for the compiler to at least know the full
| "type" of string.

I was under the impression that the standard dealt with neither typesafe
linkage nor name mangling (which you referred to later).  Overloading
resolution is a problem, however, I see that now.  Sigh.

Scott

--
Scott Meyers, Ph.D.                  Voice: 503/638-6028
C++ Consulting and Training          Fax:   503/638-6614
Author of "Effective C++"            Email: smeyers@netcom.com
  and "More Effective C++"           WWW:   http://www.teleport.com/~smeyers
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: smeyers@teleport.com (Scott Meyers)
Date: 1997/03/30
Raw View
In article <5hhm6b$82q@panix.com>,
Greg Comeau <comeau@comeaucomputing.com> wrote:
|
| It's clear.  I can remember my groans when it first dawned on me that
| this is true of say some stuff in iostreams too.  This is one that's
| nobody's fault.

Except that we have <iosfwd> for iostreams.

Scott

--
Scott Meyers, Ph.D.                  Voice: 503/638-6028
C++ Consulting and Training          Fax:   503/638-6614
Author of "Effective C++"            Email: smeyers@netcom.com
  and "More Effective C++"           WWW:   http://www.teleport.com/~smeyers
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: smeyers@teleport.com (Scott Meyers)
Date: 1997/03/30
Raw View
In article <333C008D.6839@spss.com>, Jonathan Fry  <jon@spss.com> wrote:
| The behavior I would like, and I think Scott Meyers would like as well,
| is exactly the same as if
|
|  class Foo;
|
| had appeared in translation unit 3 instead of
|
|  forward_declared_type Foo;
|
| The only difference appears in translation units in which the
| declaration of Foo is completed.  An incomplete class declaration can be
| completed only by a class or struct statement.  I want to be able to
| complete a forward declaration with a typedef or enum statement as well.

Yes, I think this is what I would like.  Oh well.  Sigh.

Scott

--
Scott Meyers, Ph.D.                  Voice: 503/638-6028
C++ Consulting and Training          Fax:   503/638-6614
Author of "Effective C++"            Email: smeyers@netcom.com
  and "More Effective C++"           WWW:   http://www.teleport.com/~smeyers
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: danm@ziplink.net (Dan Muller)
Date: 1997/03/30
Raw View
In article <01bc3bdc$f9c76710$6e23389d@larrybr1>,
SpamGuard_larrybr@microsoft.com says...
> Dan Muller <danm@ziplink.net> wrote in article
> <MPG.da39db8a62920369896cb@news.ziplink.net>...
> [prior discussion cut]
> > This makes me wonder if the following would be a wiser way to define a
> > synonym for a template instantiation:
> >
> > template<typename T> class a_template {};
> > class C : public a_template<char> {};
> >
> > This would be almost equivalent to "typedef a_template<char> C;", but
> > doesn't suffer from the forward declaration problem.
> >
> > Am I interpreting the standard correctly?
>
> This would be a neat work-around, except for the fact that
> it cuts all the constructors out.  The "typedef ... C;" allows
> C to have the constructors defined for "...", whereas once
> you inherit from "...", C only has a default constructor.

Of course, silly of me to miss this.

>
> This reminds me again of how nice it would be to have a
> way to forward all the constructors from a single base.
> Given class D : public B { ... };, I want to avoid having to
> write
>   D(blah) : B(blah) {}
>   D(hooey, looey) : B(hooey, looey) {}
>   etc.
>
> Maybe we'll see it for C++++

The real question in my mind is why the draft doesn't explicitly require
a class template instantiation to be treated as class type for purposes
such as this. After all, if instantiating a class template doesn't create
a class, what *does* it create?

--
Dan Muller   danm@ziplink.net
http://www.ziplink.net/~danm
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]





Author: Scott Meyers <smeyers@netcom.com>
Date: 1997/03/26
Raw View
Suppose I'd like to declare this simple function:

  void f(const string& s);

To do that, I have to declare class string.  I'd like to do it like
this,

  class string;

but of course string isn't really a class, it's a typedef for an
instantiation of the basic_string template:

  typedef basic_string<char> string;

So in order to declare string, I have to declare basic_string:

   template<class charT,
            class traits = char_traits<charT>,
            class Allocator = allocator<charT> >
     class basic_string;

But that requires that I declare char_traits and allocator.  The end
result is that what I'd like to write like this:

  class string;
  void f(const string& s);

I must instead write like this:

   template<class charT> struct char_traits;
   template <class T> class allocator;
   template<class charT, class traits = char_traits<charT>,
            class Allocator = allocator<charT> > class basic_string;
   typedef basic_string<char> string;
   void f(const string& s);

Is that really true?  Isn't there some way in C++ to say "this is the
name of some type, but I don't want to commit at this point to whether
it's a struct, a class, an enum, a template instantiation, or a
typedef."  I seem to recall that typename serves this purpose, but I
don't know how to apply it in this context.

BTW, I'm interested in the general case of forward-declaring a type, not
just the particular case of string.  I only chose string because it's
both familiar enough and gruesome enough to, I hope, make the problem
clear.

Thanks,

Scott
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]