Topic: incomplete enum


Author: baynes@ukpsshp1.serigate.philips.nl (Stephen Baynes)
Date: Mon, 6 Mar 1995 08:21:56 GMT
Raw View
Ulf Schuenemann (schuenem@Informatik.TU-Muenchen.DE) wrote:

: |> clamage@Eng.Sun.COM (Steve Clamage) writes:
: |>
: |> Au contraire. Pointers to a struct/class type are required to have
: |> the same representation and be interconvertable. [...]
: |> There is no such requirement on pointers to simple types. A void* is
: |> required to be able to hold a pointer to any other type. An int*
: |> and char*, for example, may be mutually incompatible.

: Interesting. Are such different pointersizes used to save some of the
: least significant bits, as ints could be aligned to wordwise addresses?
Sort of. Different pointer representations are typical on word addressed
machines. Most things (such as int) use the machines basic pointer type to
point to a word. But for things smaller than a word (such as char) one has
to add extra bits to say which character in the word.

: In article <HARKlaN0YuCB075yn@rcp.co.uk>, Duncan@rcp.co.uk (Duncan Booth) writes:
: |> > and be interconvertable.  And I can't see implementors having any
: |> > problems with such a restriction.
: |> >
: |> I can. One enum might be stored in in a char sized variable and
: |> another in an int. On some machines these would require different
: |> representations so unless you were going to insist that all enums are
: |> stored in the same size variable you cannot require that pointers to
: |> enums are convertable.

: I thought, pointer convertability is only influenced by alignment
: and not by the size to what it points.

Yes but a char sized enum would probably have char like alignment and
an int sized enum would probably have int like alignment.

However it is possible to use a 'special' pointer format that can cope
with any alignment requirements, just as void* can. This is needed for
structs - there is nothing that requires all structs to have the same
alignment requirements. Just that all pointers to structs have the same
format.

--
Stephen Baynes                              baynes@mulsoc2.serigate.philips.nl
Philips Semicondutors Ltd
Southampton                                 My views are my own.
United Kingdom




Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 3 Mar 1995 18:47:10 GMT
Raw View
|> clamage@Eng.Sun.COM (Steve Clamage) writes:
|>
|> Au contraire. Pointers to a struct/class type are required to have
|> the same representation and be interconvertable. [...]
|> There is no such requirement on pointers to simple types. A void* is
|> required to be able to hold a pointer to any other type. An int*
|> and char*, for example, may be mutually incompatible.

Interesting. Are such different pointersizes used to save some of the
least significant bits, as ints could be aligned to wordwise addresses?


In article <HARKlaN0YuCB075yn@rcp.co.uk>, Duncan@rcp.co.uk (Duncan Booth) writes:
|> > and be interconvertable.  And I can't see implementors having any
|> > problems with such a restriction.
|> >
|> I can. One enum might be stored in in a char sized variable and
|> another in an int. On some machines these would require different
|> representations so unless you were going to insist that all enums are
|> stored in the same size variable you cannot require that pointers to
|> enums are convertable.

I thought, pointer convertability is only influenced by alignment
and not by the size to what it points.


Ulf Schuenemann

--------------------------------------------------------------------
Ulf Sch   nemann
Institut f   r Informatik, Technische Universit   t M   nchen.
email: schuenem@informatik.tu-muenchen.de




Author: pstemari@eri.erinet.com (Paul J. Ste. Marie)
Date: 3 Mar 1995 21:18:56 -0500
Raw View
In article <3j7o7e$6ld@hpsystem1.informatik.tu-muenchen.de>,
Ulf Schuenemann <schuenem@Informatik.TU-Muenchen.DE> wrote:
>Interesting. Are such different pointersizes used to save some of the
>least significant bits, as ints could be aligned to wordwise addresses?

Even worse, actually.  I've seen at least one machine where the bit
saved was used to indicate indirection, in a potentially recursive
fashion.







Author: bgibbons@taligent.com (Bill Gibbons)
Date: Tue, 21 Feb 1995 23:56:49 GMT
Raw View
In article <3i5aa7$729@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve
Clamage) wrote:

> Au contraire. Pointers to a struct/class type are required to have
> the same representation and be interconvertable. So long as you don't
> tell lies about the types your code must work.
>
> (There are dangers associated with incomplete types, but conversion
> to other class pointers or to and from void* is not an issue.)
>
> There is no such requirement on pointers to simple types. A void* is
> required to be able to hold a pointer to any other type. An int*
> and char*, for example, may be mutually incompatible.

True.  But incomplete enums can still be implemented.  Since "void*" must
be capable of holding any object pointer, an implementation could store
all enumeration pointers using "void *", and convert the pointers as needed.

On many machines the implementation of "int *" and "char *" is identical.
On those machines where it is different (e.g. word-based machines), it is
likely that all enumerations would occupy entire words anyway, and would
therefore have compatible pointer types.

So there is really no problem with pointers at all.

The real reason why incomplete enumerations were not added was the lack
of member enumeration templates (similar to static data member templates):

   template<class T> struct A {
        enum E;
   };

   template<class T> enum A<T>::E { a, b, c };  // not currently allowed

The committee decided that it was inappropriate to add incomplete enums
if they couldn't be used in the above manner.  Rather than add member
enumeration templates, the committee rejected incomplete enums.


Bill Gibbons
bgibbons@taligent.com

--
Bill Gibbons
bgibbons@taligent.com




Author: Duncan@rcp.co.uk (Duncan Booth)
Date: Mon, 27 Feb 1995 11:08:01 +0000
Raw View
In article <9505703.22920@mulga.cs.mu.OZ.AU>,
fjh@munta.cs.mu.OZ.AU (Fergus Henderson) wrote:
> clamage@Eng.Sun.COM (Steve Clamage) writes:
>
> >Au contraire. Pointers to a struct/class type are required to have
> >the same representation and be interconvertable. [...]
> >There is no such requirement on pointers to simple types. A void* is
> >required to be able to hold a pointer to any other type. An int*
> >and char*, for example, may be mutually incompatible.
>
> Sure, but it would be extremely easy to add a similar requirement that
> pointers to enum types are required to have the same representation
> and be interconvertable.  And I can't see implementors having any
> problems with such a restriction.
>
I can. One enum might be stored in in a char sized variable and
another in an int. On some machines these would require different
representations so unless you were going to insist that all enums are
stored in the same size variable you cannot require that pointers to
enums are convertable.

> (BTW, is that requirement explicit in the C standard, or is it just
> something that can be deduced from the existence of pointers to
> incomplete structs?)
>


--
Duncan Booth                                             duncan@rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?
       As we anarchists say: "There's no government like no government."




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Sat, 25 Feb 1995 16:51:58 GMT
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:

>Au contraire. Pointers to a struct/class type are required to have
>the same representation and be interconvertable. [...]
>There is no such requirement on pointers to simple types. A void* is
>required to be able to hold a pointer to any other type. An int*
>and char*, for example, may be mutually incompatible.

Sure, but it would be extremely easy to add a similar requirement that
pointers to enum types are required to have the same representation
and be interconvertable.  And I can't see implementors having any
problems with such a restriction.

(BTW, is that requirement explicit in the C standard, or is it just
something that can be deduced from the existence of pointers to
incomplete structs?)

--
Fergus Henderson - fjh@munta.cs.mu.oz.au
all [L] (programming_language(L), L \= "Mercury") => better("Mercury", L) ;-)




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 18 Feb 1995 17:17:14 GMT
Raw View
ti953017@rzcipa01.rz.tu-bs.de (Andreas Rossberg) writes:

>In article <3hq2up$3dq@ra.ibr.cs.tu-bs.de>,
>Andreas Rossberg <ti953017@rzcipa01.rz.tu-bs.de> wrote:
>>In article <3hhkje$ria@engnews2.eng.sun.com>,
>>Steve Clamage <clamage@Eng.Sun.COM> wrote:
>>>
>>> class X {
>>>     enum status { status_min = -99, status_max = 99 };
>>>     ...
>>> };
>>
>>    Well, OK, but not very elegant. Usually, I want to treat enums in a more
>>    abstract way. Very few of the enums I've ever written made use of the
>>    initializer feature. This forces me to make heavy use of it, subverting
>>    the `spirit' of enums, IMHO.
>>

>    Moreover, I have to count enumerators to know that max value -
>    just as comfortable and error-prone as the times without enums...

That depends on whether "max" is intended to be exactly the value of
the largest enumerator, or merely no smaller than the largest
enumerator. For an "opaque" enum, you would pick a value larger than
any enumerator that is likely; INT_MAX, for example. The point of
an opaque enum is that the precise available values are not anyone
else's concern. Here's a more realistic example:

enum error_type { info=0, reminder=3000, warning=6000, error=9000 };

This will allow up to 3000 enumerators for each type of message, and
you can have a largest enumerator of 16383, guaranteed by the C++ rules.
(16383 requires no more bits than 9000, but 16384 does.) Notice that
this example has an implied minimum of 0 and implied maximum of 16383.

This enum type can be extended at will in implementation files
without requiring recompilation of any code which does not use
the new enumerations.
--
Steve Clamage, stephen.clamage@eng.sun.com




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 18 Feb 1995 17:21:11 GMT
Raw View
ti953017@rzcipa01.rz.tu-bs.de (Andreas Rossberg) writes:

>In article <792854260snz@wslint.demon.co.uk>,
>Kevlin Henney <Kevlin@wslint.demon.co.uk> wrote:
>>
>>Consider:
>>
>> enum CouldBeOneByte { Zero, One };
>> enum ProbablyWordSize { Low = INT_MIN, High = INT_MAX };
>>
>>Now a simple question:
>>
>> assert(sizeof(CouldBeOneByte *) == sizeof(ProbablyWordSize *));
>>
>>When you run this, is the outcome the same on every platform?
>>
>>The answer is no, therefore you cannot have forward declarations of enums.
>>

>Because of alignment?
>It's the same with

> class CouldBeByteAligned  { char c; };
> class ProbablyWordAligned { int i; }

> assert(sizeof(CouldBeByteAligned*) == sizeof(ProbablyWordAligned*));

>You have no guarantee either. Using pointers to incomplete types is always
>dangerous.

Au contraire. Pointers to a struct/class type are required to have
the same representation and be interconvertable. So long as you don't
tell lies about the types your code must work.

(There are dangers associated with incomplete types, but conversion
to other class pointers or to and from void* is not an issue.)

There is no such requirement on pointers to simple types. A void* is
required to be able to hold a pointer to any other type. An int*
and char*, for example, may be mutually incompatible.
--
Steve Clamage, stephen.clamage@eng.sun.com




Author: ti953017@rzcipa01.rz.tu-bs.de (Andreas Rossberg)
Date: 16 Feb 1995 11:04:12 GMT
Raw View
In article <792854260snz@wslint.demon.co.uk>,
Kevlin Henney <Kevlin@wslint.demon.co.uk> wrote:
>
>Consider:
>
> enum CouldBeOneByte { Zero, One };
> enum ProbablyWordSize { Low = INT_MIN, High = INT_MAX };
>
>Now a simple question:
>
> assert(sizeof(CouldBeOneByte *) == sizeof(ProbablyWordSize *));
>
>When you run this, is the outcome the same on every platform?
>
>The answer is no, therefore you cannot have forward declarations of enums.
>

Because of alignment?
It's the same with

 class CouldBeByteAligned  { char c; };
 class ProbablyWordAligned { int i; }

 assert(sizeof(CouldBeByteAligned*) == sizeof(ProbablyWordAligned*));

You have no guarantee either. Using pointers to incomplete types is always
dangerous.


 - Andreas Rossberg




Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 17 Feb 1995 20:45:04 GMT
Raw View
In article <9504606.17500@mulga.cs.mu.OZ.AU>, fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
[..]
|> Andreas Rossberg said "an incomplete enum ... which behaves very similar
|> to an incomplete class".  Why not solve the size problem in the
|> same way as is done for classes?
[..]
|>  enum Y;
|>  Y y1; // error, incomplete enum
|>  Y* y2; // ok
|>  enum Y { Y1, Y2, Y3 };
|>  Y y3; // ok
|>
|> --
|> Fergus Henderson - fjh@munta.cs.mu.oz.au
|> all [L] (programming_language(L), L \= "Mercury") => better("Mercury", L) ;-)

Excelent idea. I like this. It's very orthogonal.


I'd like to connect the topic of incomplete enums to the topic of
enums with userdefined size (remembering a discussion not long ago):

If the programmer could define the size of a enum, if he wants to,
this could especially be used to define the size of an incomplete enum:

Something like  enum int Y;
or like   enum  Y : 16;

This would allow to use the enum even where it's size is required.
The enum is defined by:

 enum Y  { y1 = -99999, y2 = 99999 };

The size of the enum derived by the previous incomplete declaration must
be big enough to hold all enumerators. The enum Y may only defined once (ODR).
NB Then, conceptually, an enum would need to have external linkage like a class.


Reading the discussion about reopening class declaration, how about:

 enum Y  { -99999 ... 99999 };

to declare the min and max of an enum. Lateron one may give the list enumerators....


Ulf Schuenemann

--------------------------------------------------------------------
Ulf Sch   nemann
Institut f   r Informatik, Technische Universit   t M   nchen.
email: schuenem@informatik.tu-muenchen.de




Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: Fri, 17 Feb 1995 13:14:38 GMT
Raw View
In article <9504606.17500@mulga.cs.mu.OZ.AU>,
Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
>clamage@Eng.Sun.COM (Steve Clamage) writes:
>
>>On the other hand, allowing
>> enum status;
>>has problems in that different enum types are allowed to have different
>>sizes. You could get inconsistent results in different compilation
>>units if the compiler had to assume some default size for the enum.
>
>Andreas Rossberg said "an incomplete enum ... which behaves very similar
>to an incomplete class".  Why not solve the size problem in the
>same way as is done for classes?
>
> class X;
> X x1; // error, incomplete class
> X* x2; // ok
> class X { /* ... */ };
> X x3; // ok
>
> enum Y;
> Y y1; // error, incomplete enum
> Y* y2; // ok
> enum Y { Y1, Y2, Y3 };
> Y y3; // ok
>

 Just that was proposed by Bill Gibbons.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: schuenem@Informatik.TU-Muenchen.DE (Ulf Schuenemann)
Date: 14 Feb 1995 16:33:45 GMT
Raw View
In article <3hhkje$ria@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
[..]
|> C++ now requires that an enum type allow any value which can be
|> represented in the number of bits required to represent the
|> defined range of the enum. So you can write in the public header:
|>  class X {
|>      enum status { status_min = -99, status_max = 99 };
|>      ...
|>  };
|> and then in the implementation file:
|>  #include "X.h"
|>  const status yucky = -98;
|>  const status ugly = -45;
|>  const status ok = 0;
|>  const status nice = 45;
|>  const status super = 98;

I always considered this bad style. And good style was if a variable
of enum-type only contained values of the corresponding enumerators ;-(
At least I remember my compiler requiring a cast:
"const X::status ok = (X::status) -98;" or more precisely a static_cast.
[NB In the absence of "using X::status;" you've to write "X::status" ]

"C++ now requires ..." - You are right, the new definition offers the
possibility for an idiom one could call 'abstract enum-types'.
They are abstract in the sense that only it's min and max value need
to be known to the compiler. The actual enumerators (pseudo-enumerators)
can be constants of the enum-type with any value between min and max.

- This programming idiom allows anyone (eg derived classes from X)
to extend the abstract enumtype by adding new pseudo-enumerators.
This, of course, may cause unexpected behavior in the implementation
of X if it relies on the sole existance of it's own pseudo-enumerators
(yucky, ..., super)

- For public abstract enum-types this allows to liberatly hide or
expose some of the pseudo-enumerators to the public.

- For consistant use in multiple translation units you should
make sure that the pseudo-enumerators have external linkage
(const defaults to interal linkage).

- For convenient use I would prefere to have the pseudo-enumerators
in the same scope as the enum-type. But having an abstract enumeration
would mean to keep them out of the class-declaration. So we would need
to add them afterwards into the namespace of the class:

 namespace X {
  extern const status yucky = static_cast<status> -98;
  ...
 };

NB: This is AFAIK not allowed in the WP!
(But there are occasional discussions about private helperfunctions etc)


Ulf Schuenemann

--------------------------------------------------------------------
Ulf Sch   nemann
Institut f   r Informatik, Technische Universit   t M   nchen.
email: schuenem@informatik.tu-muenchen.de




Author: swf@elsegundoca.ncr.com (Stan Friesen)
Date: Tue, 14 Feb 1995 17:00:18 GMT
Raw View
In article <3hhkje$ria@engnews2.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
|>
|> On the other hand, allowing
|>  enum status;
|> has problems in that different enum types are allowed to have different
|> sizes. You could get inconsistent results in different compilation
|> units if the compiler had to assume some default size for the enum.

Ah, but it would not be allowed to assume the size, any more than it
can assume the size of an incomplete class type.  In short, only references
and pointers to the type could be created until the type is complete, and
the value couldn't be accessed until the type is complete.

Of course, as you say, this really doesn't solve any meaningful
programming problems.  In fact it looks rather totally useless
to me.

--
swf@elsegundoca.attgis.com  sarima@netcom.com

The peace of God be with you.




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Tue, 14 Feb 1995 19:28:19 GMT
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:

>On the other hand, allowing
> enum status;
>has problems in that different enum types are allowed to have different
>sizes. You could get inconsistent results in different compilation
>units if the compiler had to assume some default size for the enum.

Andreas Rossberg said "an incomplete enum ... which behaves very similar
to an incomplete class".  Why not solve the size problem in the
same way as is done for classes?

 class X;
 X x1; // error, incomplete class
 X* x2; // ok
 class X { /* ... */ };
 X x3; // ok

 enum Y;
 Y y1; // error, incomplete enum
 Y* y2; // ok
 enum Y { Y1, Y2, Y3 };
 Y y3; // ok

--
Fergus Henderson - fjh@munta.cs.mu.oz.au
all [L] (programming_language(L), L \= "Mercury") => better("Mercury", L) ;-)




Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Wed, 15 Feb 1995 13:17:40 +0000
Raw View
In article <9504606.17500@mulga.cs.mu.OZ.AU>
           fjh@munta.cs.mu.OZ.AU "Fergus Henderson" writes:

>Andreas Rossberg said "an incomplete enum ... which behaves very similar
>to an incomplete class".  Why not solve the size problem in the
>same way as is done for classes?
>
>        class X;
>        X x1;   // error, incomplete class
>        X* x2;  // ok
>        class X { /* ... */ };
>        X x3;   // ok
>
>        enum Y;
>        Y y1;   // error, incomplete enum
>        Y* y2;  // ok
>        enum Y { Y1, Y2, Y3 };
>        Y y3;   // ok

Consider:

 enum CouldBeOneByte { Zero, One };
 enum ProbablyWordSize { Low = INT_MIN, High = INT_MAX };

Now a simple question:

 assert(sizeof(CouldBeOneByte *) == sizeof(ProbablyWordSize *));

When you run this, is the outcome the same on every platform?

The answer is no, therefore you cannot have forward declarations of enums.

+---------------------------+------------------------------------+
| Kevlin A P Henney         | Money confers neither intelligence |
| kevlin@wslint.demon.co.uk | nor wisdom on those who spend it   |
| Westinghouse Systems Ltd  |                                    |
+---------------------------+------------------------------------+




Author: ti953017@rzcipa01.rz.tu-bs.de (Andreas Rossberg)
Date: 15 Feb 1995 15:47:07 GMT
Raw View
In article <3hq2up$3dq@ra.ibr.cs.tu-bs.de>,
Andreas Rossberg <ti953017@rzcipa01.rz.tu-bs.de> wrote:
>In article <3hhkje$ria@engnews2.eng.sun.com>,
>Steve Clamage <clamage@Eng.Sun.COM> wrote:
>>
>> class X {
>>     enum status { status_min = -99, status_max = 99 };
>>     ...
>> };
>
>    Well, OK, but not very elegant. Usually, I want to treat enums in a more
>    abstract way. Very few of the enums I've ever written made use of the
>    initializer feature. This forces me to make heavy use of it, subverting
>    the `spirit' of enums, IMHO.
>

    Moreover, I have to count enumerators to know that max value -
    just as comfortable and error-prone as the times without enums...


 - Andreas Rossberg




Author: ti953017@rzcipa01.rz.tu-bs.de (Andreas Rossberg)
Date: 9 Feb 1995 11:55:15 GMT
Raw View
I've wondered why it's not possible to declare an incomplete enum

    enum E;

which behaves very similar to an incomplete class. IMO, it should be part
of C++ because it enables hiding private enumerations inside classes from
the general public. Consider for example,

    // interface
    class SomeClass
    {
        public:
            ...
        private:
            enum InternalType;
            ...
    };


    // implementation
    enum SomeClass::InternalType { onlyMyImplementerKnowsMe /* ... */ };

    ...

This is absolutely equivalent to what is possible for classes. Allowing
it would remove an inconsistency in the language -- with practical benefit
and almost trivial implementation.

(I know that the GNU compiler implements it (at least partially)).


 - Andreas Rossberg




Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 11 Feb 1995 06:14:06 GMT
Raw View
ti953017@rzcipa01.rz.tu-bs.de (Andreas Rossberg) writes:


>I've wondered why it's not possible to declare an incomplete enum

>    enum E;

>which behaves very similar to an incomplete class. IMO, it should be part
>of C++ because it enables hiding private enumerations inside classes from
>the general public.

This question comes up once in a while. It isn't in the language
because it doesn't solve any programming problem that can't already
be solved about as well, and creates a potential problem.

C++ now requires that an enum type allow any value which can be
represented in the number of bits required to represent the
defined range of the enum. So you can write in the public header:
 class X {
     enum status { status_min = -99, status_max = 99 };
     ...
 };
and then in the implementation file:
 #include "X.h"
 const status yucky = -98;
 const status ugly = -45;
 const status ok = 0;
 const status nice = 45;
 const status super = 98;

Except for syntax, this is equivalent to writing
 enum status { status_min=-99, yucky=-98, ugly=-45,
   ok=0, nice=45, super=98, status_max=99 };

On the other hand, allowing
 enum status;
has problems in that different enum types are allowed to have different
sizes. You could get inconsistent results in different compilation
units if the compiler had to assume some default size for the enum.
--
Steve Clamage, stephen.clamage@eng.sun.com