Topic: Feature Request: forward declarations of enums


Author: Gene Bushuyev <gbush@deja.com>
Date: Sun, 17 Dec 2000 14:53:28 GMT
Raw View
"Fergus Henderson" <fjh@cs.mu.OZ.AU> wrote in message
news:9197iu$7kb$1@mulga.cs.mu.OZ.AU...
[...]
> Suppose you have
>
> typename T;
> T * foo();
> void bar(T *);
>
> int main() {
> bar(foo());
> }
>
> and suppose T, foo() and bar() are defined in a different translation
> unit:
>
> #ifdef FOO
>   typedef int T;
> #else
>   typedef char T;
> #endif
>
> T *foo() { return 0; }
> void bar(T *) {}
>
> When compiling the first translation unit, the compiler won't know
> what the typename T will map to, so it won't know whether to emit
> a reference to `bar(int *)' or to `bar(char *)'.



I believe all the problems can be solved, if we allow this sort of anonymous
type declaration in function parameter list and in return type only, and not
in the outer scope. In order to avoid confusion I suggest calling this type
"anonymous" rather than incomplete.

void f( typename A& a )
{
   // A is declared to be an anonymous type in function scope
  A& ra = a; // OK
  A* pa = &a; // OK
  A aaa; // error: size is unknown
}

then another function cannot be defined with the same parameter list.

void f( typename B& a ){} // error: cannot redifine function void f(typename
&)

Calling function with actual parameter of anonymous type should be
prohibited.
Your example would look like this:

typename T * foo();
void bar(typename T *);

 int main() {
 bar(foo()); // error: foo() returns anonymous type
 int* i = foo();
 bar(i); // OK
}


Now regarding the problem of sizes of the pointers and references. I believe
it's not unsolvable problem. We just need to make an anonymous type - a
distinct type without size. Reference and pointer to any other type can be
converted to reference/pointer to an anonymous type.

Gene Bushuyev
---------------------------
The Constitution was handed down to guide us by a bunch of
wise old dead white guys who invented our country - Charlton Heston



---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Mon, 18 Dec 2000 14:09:44 GMT
Raw View
gbush@deja.com (Gene Bushuyev) wrote (abridged):
> I believe all the problems can be solved, if we allow this sort of
> anonymous type declaration in function parameter list and in
> return type only, and not in the outer scope.
>
> void f( typename A& a )
> {
>    // A is declared to be an anonymous type in function scope
>   A& ra = a; // OK
>   A* pa = &a; // OK
>   A aaa; // error: size is unknown
> }
>
> then another function cannot be defined with the same parameter list.

I'm afraid I don't really follow what this is intended to achieve. Is it
a kind of forward-declaration of function f()? If so what does the full
declaration look like? How does the type safety work?

Or is it some kind of genericity - eg can we somehow instantiate f() with
different concrete types for A? If so, is there an advantage over using a
template? If so, why can't templates somehow be upgraded to have the same
advantage?

You mentioned problems with templates and (void *), but I don't really
know what you mean. I rarely use (void *) in my templates. There is no
need. A template like:

    template <typename A>
    void f( A &a ) {
        A &ra = a;
        A *pa = a;
    }

does much the same job.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Mon, 18 Dec 2000 17:56:13 GMT
Raw View
thesnaguy@hotmail.com (Jim Cobban) wrote (abridged):
> I generally find that for all but the most trivial enumerations that
> it is desirable, for many reasons, to encapsulate the
> enumeration inside a class. It strikes me that the sort of
> enumeration which you are concerned with is such a non-trivial
> enumeration. If you encapsulate your enumeration inside a
> class then you will achieve your goal:
>
> class EnumWrapper;
>
> void func(EnumWrapper &);

Good suggestion. Do you find it clumsy to deal with the wrapping and
unwrapping, for example, for switch statements, equality tests and
assignments?

A wrapped enum is a different type to a naked enum, so I imagine you
rarely use naked enums.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Tue, 12 Dec 2000 21:03:06 GMT
Raw View
SUMMARY

I request that we be able to forward-declare enums, with syntax and
semantics analogous to that for classes.


EXAMPLE

    enum MyEnum;  // New forward declaration.

    void func1( MyEnum e ); // OK.


MOTIVATION

The main aim is to enable better dependency management and information
hiding. Forward declarations would allow us to declare functions which
use the enum without needing to #include the header which fully declares
it. This would allow us to avoid recompilations when that header changes.

The gain would be worth-while because the name and general type of an
enum change much less often than its list of members. Also, it is often
convenient to declare enums in the same header as the classes which use
them, and by avoiding a dependency on the full declaration we avoid a
dependency on those classes too. For example:

    /////////////////////////////////////////////////////
    // NumberFormat.h
    enum NumberFormat {
        Arabic, "1, 2, 3, 4"
        Alpha, "a, b, c, d"
        Roman, "i, ii, iii, iv"
    };

    string format( NumberFormat f, int number );

    /////////////////////////////////////////////////////
    // Page.h
    enum NumberFormat;

    class Page {
    public:
        string get_page_number( NumberFormat f ) const;
        //...
    private:
        int m_number;
    };

    /////////////////////////////////////////////////////
    // Page.cpp
    #include "Page.h"
    #include "NumberFormat.h"

    string Page::get_page_number( NumberFormat f ) const {
        return format_number( f, m_number );
    }

Here Page.cpp must have a dependency on NumberFormat.h, but other modules
which use the Page class and which don't need to call
get_formatted_number() don't need the dependency.

In current C++ we have to include NumberFormat.h in Page.h itself. This
adds overhead to each compile (because header files like NumberFormat.h
must be opened and parsed), and also increases the number of compilations
(because any change to a file like NumberFormat.h will trigger
recompilation of source files which #include it, even if indirectly and
even if they are not directly affected by the change). Also, it tends to
pollute the name space as the enum member names (Arabic, Alpha, Roman)
will be visible to a larger fraction of the source code. Even if wrapped
in a namespace, it is bad software engineering for these names to be
available unnecessarily.

These issues are especially important for large projects, where complex
structures are built up in layers with each header including several
others. If we are not careful, the dependencies increase exponentially.

A current workaround is to use ordinary integers, replacing the enum with
a typedef like:
    typedef int NumberFormat;

However, this provides less static type-safety, does not let us overload
functions on NumberFormat and generally loses the advantages of
enumerated types over ints.

My experience of forward-declared enums with Microsoft VC++ 6.0 (see
below) confirms their usefulness.

A second, relatively minor benefit is consistency with classes.
Forward-declared enums are so natural that the C++ newsgroups get several
articles a year from beginners asking variations of "Is this legal?",
usually using exactly the proposed syntax. It is very hard to see why
forward-declared enums should not be legal.


DETAIL

The syntax and semantics of forward-declared enums should follow that of
forward-declared classes closely. Thus there is little more to say here.

Such an enum would not be a fully-defined type. It could only be used in
contexts where its size or members were not needed. This would include
declarations of functions, pointers and references, and typedefs, but not
instantiations or sizeof. For example:

    enum MyEnum;  // New forward declaration.

    void func1( MyEnum e ); // OK.
    MyEnum func2(); // OK.
    void func3( MyEnum &e ); // OK.
    void func4( MyEnum *e ); // OK.
    typedef MyEnum MyEnum2;  // OK.
    void func1( int i ) // Overloading -- OK.

would all be allowed, but not:

    // int s = sizeof MyEnum; // Not OK.
    // struct S { MyEnum e; }; // Not OK.
    // inline void func1( MyEnum e ) {} // Not OK.
    // void func5() { MyEnum e; } // Not OK.

This is all analogous to classes. (On the first two, recall that with the
current C++ standard, forward-declarations of classes permit:

    class MyClass;  // Forward declaration.

    void func1( MyClass c ); // OK.
    MyClass func2(); // OK.

I mention this because not everyone realises it.)

Multiple forward-declarations of the same enum would be allowed, but only
one full declaration. Thus:

    enum MyEnum;
    enum MyEnum; // OK.
    enum MyEnum { one, two, three };
    //enum MyEnum { one, two, three }; // Not OK.

Overloading on forward-declared enums is specifically allowed. Eg:

    enum MyEnum;

    class MyClass {
    public:
        void proc( double d );
    private:
        void proc( MyEnum e );  // OK.
    };

The compiler resolves ambiguities resulting from such code as if the enum
were fully-declared.


IMPACT

This proposal would break no existing code. It does not add any new
reserved words or change the semantics of current legal syntax.

I don't believe there are any fundamental problems with implementation,
since partially-declared classes are already part of the language and
compilers are used to dealing with them. However, I don't know of any
proper implementations.

At least one compiler (Microsoft VC++ 6.0) does permit enums to be
forward-declared, but its implementation is presumably simplified by the
trick of making sizeof(enum) == sizeof(long) for all enums. I do not
intend this proposal to impose that constraint on all implementations.

That said, the VC++ 6.0 extension uses the proposed syntax and would not
be broken by this proposal. Its implementation trick is reasonable (at
least when sizeof(long) == sizeof(int)), and could be used in other
compilers if convenient.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: Ron Natalie <ron@sensor.com>
Date: Tue, 12 Dec 2000 22:15:10 GMT
Raw View

Dave Harris wrote:
>
> SUMMARY
>
> I request that we be able to forward-declare enums, with syntax and
> semantics analogous to that for classes.
>
> EXAMPLE
>
>     enum MyEnum;  // New forward declaration.

The problem with this is that enum's aren't always the same size.
Which integral type they are equivelent to can't be decided in
the absence of knowing the enumeratiors.

By the way that IS a legal declaration now.  It defines an enum
with no enumerators (which the standard says has the same behavior
as one with a single 0 enumerator).  The issue is that you can't
redefine it later.  Making this an incomplete type (rather than
a rather useless complete type as it is now), could break programs
(as does forcing it to a size larger than int as you propose might
be a way to handle the implementation).

>
> At least one compiler (Microsoft VC++ 6.0) does permit enums to be
> forward-declared, but its implementation is presumably simplified by the
> trick of making sizeof(enum) == sizeof(long) for all enums. I do not
> intend this proposal to impose that constraint on all implementations.

Then how is it supposed to work.  If the size isn't constant, how do you
know what the size is without the enumerators.

While C99 has a different idea on binding to the underlying int implementation,
the size is not constant there either (and neither are incomplete declarations).

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Gene Bushuyev" <gbush@deja.com>
Date: Tue, 12 Dec 2000 22:56:01 GMT
Raw View
"Ron Natalie" <ron@sensor.com> wrote in message
news:3A369DB9.459364D9@sensor.com...
> Dave Harris wrote:
[...]
> > EXAMPLE
> >
> >     enum MyEnum;  // New forward declaration.
>
> The problem with this is that enum's aren't always the same size.
> Which integral type they are equivelent to can't be decided in
> the absence of knowing the enumeratiors.

It should be ok, as long as one uses pointers and references only.

>
> By the way that IS a legal declaration now.  It defines an enum
> with no enumerators (which the standard says has the same behavior
> as one with a single 0 enumerator).  The issue is that you can't
> redefine it later.  Making this an incomplete type (rather than
> a rather useless complete type as it is now), could break programs
> (as does forcing it to a size larger than int as you propose might
> be a way to handle the implementation).

There can be found a solution for this. I suggest we bring some life into
"typename" keyword. So one could forward declare any type with typename:

typename enum MyEnum;

for other types where forward declaration is already in place "typename"
could become optional:

typename class A;

would be the same as:

class A;

I think there is also a use for anonymous type declaration:

typename A;

can be an alternative for using templates. The differenece between this
declaration and a template can be that every code that is allowed to use
incomplete types could be compiled immediately not waiting for
instantiatiation on a particular type. That would avoid error prone usage of
void*.

Compare:

void f(typename A&); // compiler knows how to implement the references to
incomplete type

void f(void*); // error prone solution

template<typename A> void f(A&); // problems with templates
--
-------------------------
Gene Bushuyev
I did not invent Irish dancing (Bart Simpson)


---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: Ron Natalie <ron@sensor.com>
Date: Tue, 12 Dec 2000 23:06:17 GMT
Raw View

Gene Bushuyev wrote:
>
> "Ron Natalie" <ron@sensor.com> wrote in message
> news:3A369DB9.459364D9@sensor.com...
> > Dave Harris wrote:
> [...]
> > > EXAMPLE
> > >
> > >     enum MyEnum;  // New forward declaration.
> >
> > The problem with this is that enum's aren't always the same size.
> > Which integral type they are equivelent to can't be decided in
> > the absence of knowing the enumeratiors.
>
> It should be ok, as long as one uses pointers and references only.

I don't think that's what he's asking for now (his example doesn't
show a pointer or reference, but the imposition of an incomplete
enum as a function argument).
>

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James Kuyper <kuyper@wizard.net>
Date: Wed, 13 Dec 2000 11:45:23 GMT
Raw View
Gene Bushuyev wrote:
>
> "Ron Natalie" <ron@sensor.com> wrote in message
> news:3A369DB9.459364D9@sensor.com...
> > Dave Harris wrote:
> [...]
> > > EXAMPLE
> > >
> > >     enum MyEnum;  // New forward declaration.
> >
> > The problem with this is that enum's aren't always the same size.
> > Which integral type they are equivelent to can't be decided in
> > the absence of knowing the enumeratiors.
>
> It should be ok, as long as one uses pointers and references only.

That doesn't help, there's also no guarantee that pointers to different
types of enumerators are the same size either. If one enumeration has a
size that matches or exceeds the directly addressable unit of memory on
a machine, and another enumeration has a size that's smaller than that
unit, pointers to the second enumeration type are likely to be larger
than pointers to the first type. Even if they're the same size, they're
likely to have incompatible representations.

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 13 Dec 2000 13:27:57 GMT
Raw View
James Kuyper <kuyper@wizard.net> writes:

>Gene Bushuyev wrote:
>>
>> It should be ok, as long as one uses pointers and references only.
>
>That doesn't help, there's also no guarantee that pointers to different
>types of enumerators are the same size either. If one enumeration has a
>size that matches or exceeds the directly addressable unit of memory on
>a machine, and another enumeration has a size that's smaller than that
>unit, pointers to the second enumeration type are likely to be larger
>than pointers to the first type. Even if they're the same size, they're
>likely to have incompatible representations.

Implementations for word-addressed architectures can avoid this
by either (a) allocating a whole word for each enum or (b) always
representing enum pointers as byte pointers rather than word pointers.

Anyway, such architectures are no longer commercially important and
are not likely to be so in the forseeable future.  While the C++ standard
should probably not be defined in such a way as to make implementation
on such architectures infeasible, we should not be concerned if the
standard imposes minor inefficiencies on such architectures.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: Pete Becker <petebecker@acm.org>
Date: Wed, 13 Dec 2000 14:18:26 GMT
Raw View
Gene Bushuyev wrote:
>
> > The problem with this is that enum's aren't always the same size.
> > Which integral type they are equivelent to can't be decided in
> > the absence of knowing the enumeratiors.
>
> It should be ok, as long as one uses pointers and references only.
>

Except on architectures where pointers to different sizes of integers
have different representations. (Yes, they do exist)

--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)
Contributing Editor, C/C++ Users Journal (http://www.cuj.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Wed, 13 Dec 2000 14:19:13 GMT
Raw View
ron@sensor.com (Ron Natalie) wrote (abridged):
> If the size isn't constant, how do you know what the size is
> without the enumerators.

The proposal says that forward-declared enums can only be used in
situations where the size isn't needed. Thus:
    enum MyEnum;
    void proc( MyEnum x );

would work the same way as:
    class MyClass;
    void proc( MyClass x );

Which is allowed by the current standard. ("Exceptional C++", Item 26
uses this fact, for example.) Clearly the size of MyClass can vary.

I did try to cover this in the proposal itself in order to forestall this
objection - it's one of the reasons I expanded it. I guess I wasn't clear
enough.


> [On "enum MyClass;"]
> By the way that IS a legal declaration now.  It defines an enum
> with no enumerators (which the standard says has the same behavior
> as one with a single 0 enumerator).  The issue is that you can't
> redefine it later.  Making this an incomplete type (rather than
> a rather useless complete type as it is now), could break programs...

Really? The draft standard at:
   http://www.cygnus.com/misc/wp/dec96pub/dcl.html#dcl.enum

and the ARM both give the syntax as:

   enum-specifier:
       enum identifieropt { enumerator-listopt }

which surely says the braces are required. ($1.5.1 on meta-syntax
mentions this case explicitly.) $7.2.5 uses the phrase, "if the
enumerator-list is empty", which I take to refer to things like:
    enum MyEnum {};

Was this changed between the draft and the final standard, or am I
misreading it?

If you're right it's certainly a drawback. Thanks for pointing it out. As
you say, though, the empty enumeration seems pretty pointless. One could
not instantiate it without a cast, like MyEnum(0). Is it commonly used
anywhere? If it is rare, the future standards committee might decide the
benefits outweigh this drawback. At least the old code would break with a
clear compiler error and the fix (adding empty braces) is easy.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Wed, 13 Dec 2000 14:19:53 GMT
Raw View
gbush@deja.com (Gene Bushuyev) wrote (abridged):
> It should be ok, as long as one uses pointers and references only.

As I've said in another post (and in the original proposal), one
shouldn't need to know the size to declare a function, either.

   class MyClass;
   void proc( MyClass );

is already legal even though sizeof(MyClass) is not known.


> I think there is also a use for anonymous type declaration:
>
> typename A;
>
> can be an alternative for using templates. The differenece between this
> declaration and a template can be that every code that is allowed to
> use incomplete types could be compiled immediately not waiting for
> instantiatiation on a particular type. That would avoid error prone
> usage of void*.
>
> void f(typename A&); // compiler knows how to implement the references
>                      // to imcomplete type.

It's an interesting idea. However...

The size of a pointer or reference may depend on what it is pointing to,
so this wouldn't get us any further where sizes need to be known. For
example, on some machines sizeof(char *) != sizeof(int *). This is
because a (char *) may be represented by an (int *) plus a small offset
to select one byte from the int.

Incidently, this applies even if we know that the type is an enum. An
enum with a small range may effectively be stored in a char, and one with
a larger range in an int, so the same pointer representation issues
arise.

A more serious problem concerns overloading and typedef. Consider:

    typename A;
    typename B;

    class Test {
        virtual void f( A &a );
        virtual void f( B &b );
    };

Is this legal? If we later have:

    class A {};
    class B {};

then it is, but if instead we have:

    class A {};
    typedef A B;

so that A and B name the same type, then Test::f() becomes multiply
declared, which is illegal. In any case we don't know how many slots to
allocate in the vtbl.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 13 Dec 2000 14:23:11 GMT
Raw View
Ron Natalie <ron@sensor.com> writes:

>Dave Harris wrote:
>>     enum MyEnum;  // New forward declaration.
>
>By the way that IS a legal declaration now.  It defines an enum
>with no enumerators (which the standard says has the same behavior
>as one with a single 0 enumerator).

You're mistaken, I'm pretty sure.
`enum MyEnum {};' is allowed, but `enum MyEnum;' is not.

>> At least one compiler (Microsoft VC++ 6.0) does permit enums to be
>> forward-declared, but its implementation is presumably simplified by the
>> trick of making sizeof(enum) == sizeof(long) for all enums. I do not
>> intend this proposal to impose that constraint on all implementations.
>
>Then how is it supposed to work.

It should work as it has in GNU C (but not GNU C++, as it happens)
for many years: enums can be forward declared, and such enums have
incomplete types until they have been defined.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 13 Dec 2000 14:23:25 GMT
Raw View
Ron Natalie <ron@sensor.com> writes:
>[someone wrote:]
>> It should be ok, as long as one uses pointers and references only.
>
>I don't think that's what he's asking for now (his example doesn't
>show a pointer or reference, but the imposition of an incomplete
>enum as a function argument).

The example involved only the *declaration* of a function with an
incomplete enum as a function argument, not the *definition* of such
a function.  It's OK to declare functions with incomplete argument
types, so long as those types are completed before the function
definition.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James.Kanze@dresdner-bank.com
Date: Wed, 13 Dec 2000 14:56:28 GMT
Raw View
In article <917oqm$mp9$1@mulga.cs.mu.OZ.AU>,
  fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> Ron Natalie <ron@sensor.com> writes:
> >[someone wrote:]
> >> It should be ok, as long as one uses pointers and references only.

> >I don't think that's what he's asking for now (his example doesn't
> >show a pointer or reference, but the imposition of an incomplete
> >enum as a function argument).

> The example involved only the *declaration* of a function with an
> incomplete enum as a function argument, not the *definition* of such
> a function.  It's OK to declare functions with incomplete argument
> types, so long as those types are completed before the function
> definition.

Or the function is called?

Note that the fact that you can foreward declare classes pretty much
means that all class pointers have to look alike.  Allowing the
foreward declaration of enum's would have the same effect on enum's.
(I don't know if this is a problem, but it is an aspect that would
have to be considered.)

--
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(069)63198627


Sent via Deja.com
http://www.deja.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James.Kanze@dresdner-bank.com
Date: Wed, 13 Dec 2000 15:00:01 GMT
Raw View
In article <917oms$mjh$1@mulga.cs.mu.OZ.AU>,
  fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:

> It should work as it has in GNU C (but not GNU C++, as it happens)
> for many years: enums can be forward declared, and such enums have
> incomplete types until they have been defined.

There's a slight difference between C and C++ here.  In C, an enum
must be at least as big as an int; in C++, it can be as small as a
char.  In the only actual cases I know of where data pointers have
different sizes, it is char* that is different from all of the others.

--
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(069)63198627


Sent via Deja.com
http://www.deja.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James Kuyper <kuyper@wizard.net>
Date: Wed, 13 Dec 2000 15:52:34 GMT
Raw View
Fergus Henderson wrote:
>
> James Kuyper <kuyper@wizard.net> writes:
>
> >Gene Bushuyev wrote:
> >>
> >> It should be ok, as long as one uses pointers and references only.
> >
> >That doesn't help, there's also no guarantee that pointers to different
                                   ^^^^^^^^^^^^
> >types of enumerators are the same size either. If one enumeration has a
> >size that matches or exceeds the directly addressable unit of memory on
> >a machine, and another enumeration has a size that's smaller than that
> >unit, pointers to the second enumeration type are likely to be larger
> >than pointers to the first type. Even if they're the same size, they're
> >likely to have incompatible representations.
>
> Implementations for word-addressed architectures can avoid this
> by either (a) allocating a whole word for each enum or (b) always
> representing enum pointers as byte pointers rather than word pointers.
>
> Anyway, such architectures are no longer commercially important and
> are not likely to be so in the forseeable future.  While the C++ standard
> should probably not be defined in such a way as to make implementation
> on such architectures infeasible, we should not be concerned if the
> standard imposes minor inefficiencies on such architectures.

I was describing what the standard currently says, and giving an example
of why it says it. Obviously, future versions could provide guarantees
about pointer representations that the current standard doesn't, but I
don't think they're likely to.

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: Ron Natalie <ron@sensor.com>
Date: Wed, 13 Dec 2000 16:22:34 GMT
Raw View

James.Kanze@dresdner-bank.com wrote:
>
> In article <917oms$mjh$1@mulga.cs.mu.OZ.AU>,
>   fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
>
> > It should work as it has in GNU C (but not GNU C++, as it happens)
> > for many years: enums can be forward declared, and such enums have
> > incomplete types until they have been defined.
>
> There's a slight difference between C and C++ here.  In C, an enum
> must be at least as big as an int; in C++, it can be as small as a
> char.  In the only actual cases I know of where data pointers have
> different sizes, it is char* that is different from all of the others.
>

Not in C99, while it is different between C and C++, what C99 permits
is either char, int, or unsigned int.  C++ says any integral type, but
not bigger than int or unsigned int unless necessary to represent the
enumerators.

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: scotts@ims.com (Scott Schurr)
Date: Wed, 13 Dec 2000 19:15:10 GMT
Raw View
In article <3A36FFD6.35CE0F31@wizard.net>, James Kuyper <kuyper@wizard.net> writes:
|> Gene Bushuyev wrote:
|> >
|> > "Ron Natalie" <ron@sensor.com> wrote in message
|> > news:3A369DB9.459364D9@sensor.com...
|> > > Dave Harris wrote:
|> > [...]
|> > > > EXAMPLE
|> > > >
|> > > >     enum MyEnum;  // New forward declaration.
|> > >
|> > > The problem with this is that enum's aren't always the same size.
|> > > Which integral type they are equivelent to can't be decided in
|> > > the absence of knowing the enumeratiors.
|> >
|> > It should be ok, as long as one uses pointers and references only.
|>
|> That doesn't help, there's also no guarantee that pointers to different
|> types of enumerators are the same size either. If one enumeration has a
|> size that matches or exceeds the directly addressable unit of memory on
|> a machine, and another enumeration has a size that's smaller than that
|> unit, pointers to the second enumeration type are likely to be larger
|> than pointers to the first type. Even if they're the same size, they're
|> likely to have incompatible representations.

Okay.  That means that a forward declaration of an enum needs to
say something about the size of the enum.  According to 7.2[5]:

  The underlying type of an enumeration is an integral type that can
  represent all of the enumerator values defined in the enumeration.
  It is implementation-defined which integral type is used as the
  underlying type for an enumeration except that the underlying type
  shall not be larger than int unless the enumerator cannot fit in an
  int or unsigned int.

So any enum must have an underlying type that is one of the built-in
integer types.  If we include that information in the forward
declaration then we are done, right?

I'm no language lawyer, but just for something to sling mud at,
consider the following possibility.

  enum MyEnum<int>;              // Proposed forward declaration.

In place of the "int" in the example, any of the signed and unsigned
integer types and bool would be allowed.  I think a complete list
(from section 3.9.1, Fundamental types) would be:

  bool
  char
  signed char
  unsigned char
  short int
  signed short int
  unsigned short int
  int
  signed int
  unsigned int
  long int
  signed long int
  unsigned long int
  wchar_t

Note that this declaration would *not* mandate that the enum match the
size of the forward declared type.  The forward declaration only
states that:

  1. All enumerator values can be represented by the forward declared
     underlying type.

  2. All forward declared enumerations of a particular underlying
     type always occupy the same amount of storage.

Rule 1 allows a forward declaration of

  enum MySmallEnum<bool>;

to occupy the space of an int, just as the standard allows today.  But
an implementation would also allow the enum to be stored in some
region smaller than an int - ass small as one bit.  That's all up to
the implementation.

On the other hand, any conforming implementation ought to reject the
following:

  enum MyBadEnum<bool>;          // Forward declaration

  enum MyBadEnum {a, b, c};      // Error!  Enumerators exceed forward
                                 // declared storage type.

This example should be rejected by the compiler even though the actual
underlying type might very well allow three unique values to be
represented.

An example of rule 2 would be:

  enum AEnum<bool>;
  enum BEnum<bool>;
  enum CEnum<int>;

  sizeof (AEnum) == sizeof (BEnum);    // Always returns true
  sizeof (aEnum) == sizeof (CEnum);    // Implementation defined

One hole I can see in the proposal involves what to do with the
following case.  Consider a forward declaration in one file and
a different local definition in two other files:

file: forwardDeclaration.h
  enum myConfusedEnum<int>;      // Forward declaration in one file

file: useForwardA.C
  #include "forwardDeclaration.h"
  enum myConfusedEnum {a, b, c}; // A local definition.  Hurrah!

file: useForwardB.C
  #include "forwardDeclaration.h"
  enum myConfusedEnum {d, e};    // A different local definition.  Boo!

This is clearly an ill-formed program, since "myConfusedEnum" has
two unique definitions.  But the compiler cannot see both definitions
since they are in separate compilation units.  Since the compiler
cannot detect the error, what we probably get out of this is undefined
behavior.

I think that not being able to forward declare an enum is a real pain.
There have been several cases where it has driven an enumeration list
into an interface where otherwise I could have hidden it.  I believe
the lack of forward declaration of enums is a real flaw in the current
language.

--------------------------------------
Scott Schurr
  Integrated Measurement Systems, Inc.
  Voice: (503) 626-7117
  Fax:   (503) 644-6969
  Email: scotts@ims.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Wed, 13 Dec 2000 20:50:12 GMT
Raw View
James.Kanze@dresdner-bank.com () wrote (abridged):
> > The example involved only the *declaration* of a function with an
> > incomplete enum as a function argument, not the *definition* of such
> > a function.  It's OK to declare functions with incomplete argument
> > types, so long as those types are completed before the function
> > definition.
>
> Or the function is called?

Indeed.


> Note that the fact that you can foreward declare classes pretty much
> means that all class pointers have to look alike.  Allowing the
> foreward declaration of enum's would have the same effect on enum's.
> (I don't know if this is a problem, but it is an aspect that would
> have to be considered.)

I agree it should be considered. When I wrote the proposal I focussed on
the enums themselves, not on pointers and references to them. I'll update
the proposal when the discussion is over.

It seems to me we have 3 options:

(1) Forbid pointers and references to forward-declared enums.

This is probably the simplest to implement, but means that we can
sometimes use enums where we can't use pointers to them, which is a bit
bizarre.

(2) Pointers and references to forward-declared enums are themselves only
partially declared, and they become complete when the enum does.

For example:
    enum MyEnum;
    void proc( MyEnum *p ); // OK
    // struct s { MyEnum *p; }; // Not OK; partial pointer.

This is an annoying inconsistency with the rules for classes, but it is
probably the best we can do without risking incompatibility with existing
code.

(3) Pointers and references to forward-declared enums are full types.

This implies sizeof(enum *) is the same regardless of the number of
members in the enum. It matters for implementations where sizeof(char *)
!= sizeof(int *), where it implies enums themselves must be at least as
big as shorts (but at least it can always be implemented).

I am not entirely comfortable with this constraint. It is incompatible
with C++98 and C99, which is bad. It would be a move away from
efficiency, which is bad too. On the other hand, it only affects a small
number of platforms and I doubt it will cause problems to me personally.

I don't feel very strongly about any of these choices, partly because in
my experience pointers and references to enums are much rarer than the
enums themselves. For the sake of concreteness I'll probably suggest (2).

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: "Jim Cobban" <thesnaguy@hotmail.com>
Date: Thu, 14 Dec 2000 13:15:14 GMT
Raw View
"Dave Harris" <brangdon@cix.compulink.co.uk> wrote in message
news:memo.20001212200204.60967F@a.btinternet.com...
>
> SUMMARY
>
> I request that we be able to forward-declare enums, with syntax and
> semantics analogous to that for classes.

I generally find that for all but the most trivial enumerations that it is
desirable, for many reasons, to encapsulate the enumeration inside a class.
It strikes me that the sort of enumeration which you are concerned with is
such a non-trivial enumeration. If you encapsulate your enumeration inside a
class then you will achieve your goal:

class EnumWrapper;

void func(EnumWrapper &);

This works because it resolves the problem with forward definition of
enumerations that Ron Natalie described.  The compiler does not have to know
how much storage the enumeration takes up.  It only needs to know how much
storage a reference to a class takes up, which is constant for all classes.
If you add enumeration constants, or change the size of the underlying
implementation, or even add additional function onto the enumeration (such
as input or output to streams, assignment from integers, and so on), only
the code which is affected by the change to the EnumWrapper class is
recompiled.


---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: brangdon@cix.compulink.co.uk (Dave Harris)
Date: Thu, 14 Dec 2000 13:16:59 GMT
Raw View
fjh@cs.mu.OZ.AU (Fergus Henderson) wrote (abridged):
> Anyway, such architectures are no longer commercially important and
> are not likely to be so in the forseeable future.  While the C++
> standard should probably not be defined in such a way as to make
> implementation on such architectures infeasible, we should not
> be concerned if the standard imposes minor inefficiencies on
> such architectures.

I'm not so sure about this. If we were designing a new language from
scratch, I might agree. However, this would be an incompatible change
from C++98. Potentially quite a serious one. For example, people might
have PODs with enums stored as binary data, as in:

    struct S {
        enum Answer { Yes, No, Maybe } answer;
        int confidence;
    };

    void save( int fd, const S &s ) {
        write( fd, (const char *) &s, sizeof S );
    }

and a change to sizeof(Answer) would make it hard to preserve binary
compatibility of the data. Obviously this sort of thing is risky anyway,
and at the vendor's whim, but we should hesitate before *forcing* vendors
to break their customers data.

It would also be incompatible with C99. Even though it may only affect a
small number of platforms, incompatibilities of this sort can take up a
disproportionate effort in terms of documentation and language lawyering.
As for example the difference in sizeof('a'), which everyone has to note
even though nobody cares.

It is especially bothersome in that it would lead to less efficient
programs. It might encourage some people to use chars instead of enums,
which would be bad engineering. It might encourage people to use C++98
instead of the new C++xx, which would retard acceptance of the new
standard. It might even encourage them to use C instead of C++.

Any change which makes C more efficient than C++ needs to be considered
carefully. The political impact may be disproportionate to the number of
platforms affected.

(I have suggested two other approaches to the pointer issue in a another
article, posted at the same time as this one. These arguments don't
necessarily break the original proposal.)

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James Kuyper <kuyper@wizard.net>
Date: Thu, 14 Dec 2000 13:19:52 GMT
Raw View
Ron Natalie wrote:
>
> James.Kanze@dresdner-bank.com wrote:
> >
> > In article <917oms$mjh$1@mulga.cs.mu.OZ.AU>,
> >   fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
...
> > There's a slight difference between C and C++ here.  In C, an enum
> > must be at least as big as an int; in C++, it can be as small as a
> > char.  In the only actual cases I know of where data pointers have
> > different sizes, it is char* that is different from all of the others.
> >
>
> Not in C99, while it is different between C and C++, what C99 permits
> is either char, int, or unsigned int.

C99 6.7.2.2p4: "Each enumerated type shall be compatible with char, a
signed integer type, or an
unsigned integer type." Note that 6.2.5p4 defines the signed integer
types as including both standard signed types and extended signed types.
Paragraph 6 does the same for unsigned types, even going so far as to
include _Bool.

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Thu, 14 Dec 2000 13:21:38 GMT
Raw View
scotts@ims.com (Scott Schurr) writes:

>So any enum must have an underlying type that is one of the built-in
>integer types.  If we include that information in the forward
>declaration then we are done, right?
>
>I'm no language lawyer, but just for something to sling mud at,
>consider the following possibility.
>
>  enum MyEnum<int>;              // Proposed forward declaration.

That syntax is awful, since it suggests a template type.
(What happens if further down the track we want to add
template enums, for example?)

There is actually prior art for this proposal: Microsoft's new
language `C#' supports something similar to this.  If you're going to
go with something like this, you could do worse than choosing the same
syntax as in C#, which IIRC is `enum MyEnum : int { ... }'.
For forward declarations, that would become just `enum MyEnum : int'.

But actually I don't much like the C# syntax either, since it suggests
inheritance, but the semantics are different.  I'd prefer something
like `MyType enum MyEnum;' e.g.

 short enum MyShortEnum;
 long enum MyLongEnum;
 int_least16_t enum AnotherEnum;

>In place of the "int" in the example, any of the signed and unsigned
>integer types and bool would be allowed.

If you allow `char', there's no point allowing bool, since bool can't
be smaller than `char' anyway.

>Note that this declaration would *not* mandate that the enum match the
>size of the forward declared type.

I think in C# the declaration does mandate that the enum representation
match that of the specified type.

>Rule 1 allows a forward declaration of
>
>  enum MySmallEnum<bool>;
>
>to occupy the space of an int, just as the standard allows today.  But
>an implementation would also allow the enum to be stored in some
>region smaller than an int - ass small as one bit.

That's not possible, since C requires all objects (except bitfields)
to consist of a contiguous sequence of bytes.

>One hole I can see in the proposal involves what to do with the
>following case.  Consider a forward declaration in one file and
>a different local definition in two other files:
>
>file: forwardDeclaration.h
>  enum myConfusedEnum<int>;      // Forward declaration in one file
>
>file: useForwardA.C
>  #include "forwardDeclaration.h"
>  enum myConfusedEnum {a, b, c}; // A local definition.  Hurrah!
>
>file: useForwardB.C
>  #include "forwardDeclaration.h"
>  enum myConfusedEnum {d, e};    // A different local definition.  Boo!
>
>This is clearly an ill-formed program, since "myConfusedEnum" has
>two unique definitions.  But the compiler cannot see both definitions
>since they are in separate compilation units.  Since the compiler
>cannot detect the error, what we probably get out of this is undefined
>behavior.

Yes, that would be a violation of the One Definition Rule.
The problem for enums is no worse than the corresponding problem for
classes.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: fjh@cs.mu.OZ.AU (Fergus Henderson)
Date: Thu, 14 Dec 2000 14:00:37 GMT
Raw View
brangdon@cix.compulink.co.uk (Dave Harris) writes:
>[someone wrote:]
>> I think there is also a use for anonymous type declaration:
>>
>> typename A;
>>
>> can be an alternative for using templates. The differenece between this
>> declaration and a template can be that every code that is allowed to
>> use incomplete types could be compiled immediately not waiting for
>> instantiatiation on a particular type. That would avoid error prone
>> usage of void*.
>>
>> void f(typename A&); // compiler knows how to implement the references
>>                      // to imcomplete type.
>
>It's an interesting idea. However...
>The size of a pointer or reference may depend on what it is pointing to,
...
>A more serious problem concerns overloading and typedef.

Another serious problem is related to name mangling when generating
references to externally defined names.

Suppose you have

 typename T;
 T * foo();
 void bar(T *);

 int main() {
  bar(foo());
 }

and suppose T, foo() and bar() are defined in a different translation
unit:

 #ifdef FOO
   typedef int T;
 #else
   typedef char T;
 #endif

 T *foo() { return 0; }
 void bar(T *) {}

When compiling the first translation unit, the compiler won't know
what the typename T will map to, so it won't know whether to emit
a reference to `bar(int *)' or to `bar(char *)'.

--
Fergus Henderson <fjh@cs.mu.oz.au>  |  "I have always known that the pursuit
                                    |  of excellence is a lethal habit"
WWW: <http://www.cs.mu.oz.au/~fjh>  |     -- 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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James.Kanze@dresdner-bank.com
Date: Thu, 14 Dec 2000 15:39:44 GMT
Raw View
In article <memo.20001213204751.24539A@a.btinternet.com>,
  brangdon@cix.compulink.co.uk wrote:
> James.Kanze@dresdner-bank.com () wrote (abridged):
> > > The example involved only the *declaration* of a function with
> > > an incomplete enum as a function argument, not the *definition*
> > > of such a function.  It's OK to declare functions with
> > > incomplete argument types, so long as those types are completed
> > > before the function definition.

> > Or the function is called?

> Indeed.

> > Note that the fact that you can foreward declare classes pretty
> > much means that all class pointers have to look alike.  Allowing
> > the foreward declaration of enum's would have the same effect on
> > enum's.  (I don't know if this is a problem, but it is an aspect
> > that would have to be considered.)

> I agree it should be considered. When I wrote the proposal I
> focussed on the enums themselves, not on pointers and references to
> them. I'll update the proposal when the discussion is over.

> It seems to me we have 3 options:

> (1) Forbid pointers and references to forward-declared enums.

> This is probably the simplest to implement, but means that we can
> sometimes use enums where we can't use pointers to them, which is a
> bit bizarre.

It is also different from what you can do with all other incomplete
types.

> (2) Pointers and references to forward-declared enums are themselves
> only partially declared, and they become complete when the enum
> does.

> For example:
>     enum MyEnum;
>     void proc( MyEnum *p ); // OK
>     // struct s { MyEnum *p; }; // Not OK; partial pointer.

> This is an annoying inconsistency with the rules for classes, but it
> is probably the best we can do without risking incompatibility with
> existing code.

As you say, it is still another special rule.  I really doubt that it
will fly.

> (3) Pointers and references to forward-declared enums are full types.

> This implies sizeof(enum *) is the same regardless of the number of
> members in the enum. It matters for implementations where
> sizeof(char *) != sizeof(int *), where it implies enums themselves
> must be at least as big as shorts (but at least it can always be
> implemented).

> I am not entirely comfortable with this constraint. It is
> incompatible with C++98 and C99, which is bad. It would be a move
> away from efficiency, which is bad too. On the other hand, it only
> affects a small number of platforms and I doubt it will cause
> problems to me personally.

Both C++98 and C99 carried on the principle from C90.  As Fergus
points out, it might be time to reconsider.  I wouldn't like to make
an implementation on a word addressed machine impossible, but I don't
have too many problems if the only constraint is that they cannot
implement an enum as a char.  They aren't that common, to begin with,
and are becoming less so.  And many (most?, all?) implementations
allocate an int minimum for an enum anyway, even when there would
otherwise be no difference.

> I don't feel very strongly about any of these choices, partly
> because in my experience pointers and references to enums are much
> rarer than the enums themselves. For the sake of concreteness I'll
> probably suggest (2).

I'd go with 3.  I think that this would find the most support.

--
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(069)63198627


Sent via Deja.com
http://www.deja.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James.Kanze@dresdner-bank.com
Date: Thu, 14 Dec 2000 16:08:43 GMT
Raw View
In article <3A381C5C.43D574B2@wizard.net>,
  James Kuyper <kuyper@wizard.net> wrote:
> Ron Natalie wrote:
> >
> > James.Kanze@dresdner-bank.com wrote:
> > >
> > > In article <917oms$mjh$1@mulga.cs.mu.OZ.AU>,
> > >   fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> ...
> > > There's a slight difference between C and C++ here.  In C, an enum
> > > must be at least as big as an int; in C++, it can be as small as a
> > > char.  In the only actual cases I know of where data pointers have
> > > different sizes, it is char* that is different from all of the
others.

> > Not in C99, while it is different between C and C++, what C99
> > permits is either char, int, or unsigned int.

> C99 6.7.2.2p4: "Each enumerated type shall be compatible with char,
> a signed integer type, or an unsigned integer type." Note that
> 6.2.5p4 defines the signed integer types as including both standard
> signed types and extended signed types.  Paragraph 6 does the same
> for unsigned types, even going so far as to include _Bool.

Paragraph 6.2.5 doesn't even acknowledge that enum types exist.  Enum
constants have type int.

Are there C implementations where an enum type is not compatible with
int?

--
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(069)63198627


Sent via Deja.com
http://www.deja.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: Thu, 14 Dec 2000 18:46:26 GMT
Raw View
James.Kanze@dresdner-bank.com wrote:

[...]

> Both C++98 and C99 carried on the principle from C90.  As Fergus
> points out, it might be time to reconsider.  I wouldn't like to make
> an implementation on a word addressed machine impossible, but I don't
> have too many problems if the only constraint is that they cannot
> implement an enum as a char.  They aren't that common, to begin with,
> and are becoming less so.  And many (most?, all?) implementations
> allocate an int minimum for an enum anyway, even when there would
> otherwise be no difference.

I'd expect _especially_ word-addressed machines to use int for enums,
since I guess it's much faster there.

[...]

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James.Kanze@dresdner-bank.com
Date: Thu, 14 Dec 2000 19:33:10 GMT
Raw View
In article <memo.20001213204825.24539B@a.btinternet.com>,
  brangdon@cix.compulink.co.uk wrote:
> fjh@cs.mu.OZ.AU (Fergus Henderson) wrote (abridged):
> > Anyway, such architectures are no longer commercially important and
> > are not likely to be so in the forseeable future.  While the C++
> > standard should probably not be defined in such a way as to make
> > implementation on such architectures infeasible, we should not
> > be concerned if the standard imposes minor inefficiencies on
> > such architectures.

> I'm not so sure about this. If we were designing a new language from
> scratch, I might agree. However, this would be an incompatible
> change from C++98. Potentially quite a serious one. For example,
> people might have PODs with enums stored as binary data, as in:

>     struct S {
>         enum Answer { Yes, No, Maybe } answer;
>         int confidence;
>     };

>     void save( int fd, const S &s ) {
>         write( fd, (const char *) &s, sizeof S );
>     }

> and a change to sizeof(Answer) would make it hard to preserve binary
> compatibility of the data. Obviously this sort of thing is risky
> anyway, and at the vendor's whim, but we should hesitate before
> *forcing* vendors to break their customers data.

Before considering this, we should ask: 1) how many C++
implementations are there in reality on word addressed machines, 2)
how many C++ implementations actually implement any enum as anything
smaller than an int, and 3) is the intersection of these two sets
non-empty?  Given that I suspect the answer to the first two questions
is very small anyway, there is a good chance that the answer to the
third is yes.  In which case, no implementation would be affected.

> It would also be incompatible with C99.

How?  C99 doesn't have enum types.  In C99, an enum declaration
defines an int, and all enum constants have type int.  (This is
probably why most C++ don't support smaller enum types.)

> Even though it may only
> affect a small number of platforms, incompatibilities of this sort
> can take up a disproportionate effort in terms of documentation and
> language lawyering.  As for example the difference in sizeof('a'),
> which everyone has to note even though nobody cares.

> It is especially bothersome in that it would lead to less efficient
> programs. It might encourage some people to use chars instead of
> enums, which would be bad engineering. It might encourage people to
> use C++98 instead of the new C++xx, which would retard acceptance of
> the new standard. It might even encourage them to use C instead of
> C++.

In practice, if the size is important, I use either signed or unsigned
char.  Of course, it will be encapsulated in a class, whose interface
will only show the enum type.  But if you want to be sure that the
values actually do only occupy one byte, it's the only way.

Note that all we would be doing is *restricting* the implementations
freedom a little.  And only on a very small set of platforms.  And a
freedom that, as far as I know, no implementation actually uses.  (I
think allowing different sized enum's was an innovation of the
committee.  So that any older compilers would use int anyway.)

--
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(069)63198627


Sent via Deja.com
http://www.deja.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: scott_schurr@my-deja.com
Date: Thu, 14 Dec 2000 19:51:36 GMT
Raw View
In article <9198rj$8k3$1@mulga.cs.mu.OZ.AU>,
  fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> scotts@ims.com (Scott Schurr) writes:
>
> >So any enum must have an underlying type that
is one of the built-in
> >integer types.  If we include that information
in the forward
> >declaration then we are done, right?
> >
> >I'm no language lawyer, but just for something
to sling mud at,
> >consider the following possibility.
> >
> >  enum MyEnum<int>;              // Proposed
forward declaration.
>
> That syntax is awful, since it suggests a
template type.
> (What happens if further down the track we want
to add
> template enums, for example?)

Thank you.  Mud appreciated.  I was actually
thinking
of the C++ casting syntax when I made the
suggestion.
But I don't have any attachment to the proposed
syntax.

> But actually I don't much like the C# syntax
either, since it suggests
> inheritance, but the semantics are different.
I'd prefer something
> like `MyType enum MyEnum;' e.g.
>
>  short enum MyShortEnum;
>  long enum MyLongEnum;
>  int_least16_t enum AnotherEnum;

Hmmm.  Your proposal is fine with me.  But it
doesn't
visually flag me that a forward declaration is
happening.
At a quick glance it looks like a local variable
declaration
of a short, long, or int_least16_t respectively.
However,
if this syntax works better with the C++ standard
from the
perspective of the C++ Committee I'll learn to
love it.

It would be nice if the enum forward declaration
syntax
were akin to the syntax for a class or struct
forward
declaration, i.e.

  class MyForwardDeclaredClass;
  struct MyForwardDeclaredStruct;
  enum MyForwardDeclaredEnum???; // Size needed
here

However, there may be practical or esthetic
reasons for
not going this way.

> >In place of the "int" in the example, any of
the signed and unsigned
> >integer types and bool would be allowed.
>
> If you allow `char', there's no point allowing
bool, since bool can't
> be smaller than `char' anyway.

Whatever makes the C++ Committee happy makes
me happy.

So, if we change the original suggested syntax to
Fergus Henderson's suggested syntax, we still have
a
potential solution to the problem of enum forward
declarations.

Are there any difficulties that people would like
to point
out regarding the proposal?  In specific, are
there
serious problems associated with including the
size of
the enum in the forward declaration?  Does
including the
size in the forward declaration fix the problem
that
prevented the standard from allowing forward
declaration
of enums in the first place?  Is there another
difficulty
lurking under the surface?

Thank you.

--------------------------------------
Scott Schurr
  Integrated Measurement Systems, Inc.
  Voice: (503) 626-7117
  Fax:   (503) 644-6969
  Email: scotts@ims.com
--------------------------------------


Sent via Deja.com
http://www.deja.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James Kuyper <kuyper@wizard.net>
Date: Fri, 15 Dec 2000 14:04:19 GMT
Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <3A381C5C.43D574B2@wizard.net>,
>   James Kuyper <kuyper@wizard.net> wrote:
> > Ron Natalie wrote:
> > >
> > > James.Kanze@dresdner-bank.com wrote:
> > > >
> > > > In article <917oms$mjh$1@mulga.cs.mu.OZ.AU>,
> > > >   fjh@cs.mu.OZ.AU (Fergus Henderson) wrote:
> > ...
> > > > There's a slight difference between C and C++ here.  In C, an enum
> > > > must be at least as big as an int; in C++, it can be as small as a
> > > > char.  In the only actual cases I know of where data pointers have
> > > > different sizes, it is char* that is different from all of the
> others.
>
> > > Not in C99, while it is different between C and C++, what C99
> > > permits is either char, int, or unsigned int.
>
> > C99 6.7.2.2p4: "Each enumerated type shall be compatible with char,
> > a signed integer type, or an unsigned integer type." Note that
> > 6.2.5p4 defines the signed integer types as including both standard
> > signed types and extended signed types.  Paragraph 6 does the same
> > for unsigned types, even going so far as to include _Bool.
>
> Paragraph 6.2.5 doesn't even acknowledge that enum types exist.

Agreed. However, it does define the term "signed integer types", a term
which is used in 6.7.2.2p4 while describing the (lack of) restrictions
on the compatible type. In C99, the compatible type can be any integer
type, standard or extended, signed or unsigned, subject only to the
constraint that it must be able to hold all the values in the
enumeration.

>  Enum
> constants have type int.

Correct, which is why it would make no sense to define an enumeration as
being compatible with any type larger than int. However, it would make
sense in some contexts to use a type smaller than int as the compatible
type. That's particularly true if int_fast8_t is smaller than 'int'.

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]





Author: James Kuyper <kuyper@wizard.net>
Date: Fri, 15 Dec 2000 15:33:00 GMT
Raw View
James.Kanze@dresdner-bank.com wrote:
>
> In article <memo.20001213204825.24539B@a.btinternet.com>,
>   brangdon@cix.compulink.co.uk wrote:
...
> > It would also be incompatible with C99.
>
> How?  C99 doesn't have enum types.  In C99, an enum declaration
> defines an int,

Incorrect - as I've already pointed out elsewhere.

> ... and all enum constants have type int.

Correct.

---
[ 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                ]
[ Note that the FAQ URL has changed!  Please update your bookmarks.     ]