[comp.lang.c++] errata in C++ Primer

stan@kaiser.UUCP (s Lippman) (06/19/89)

My ``C++ Primer'' is based on a draft of Bjarne's 
C++ Reference Manual (and matching in-house pre-
release versions Release 2.0).  Subsequent to the 
delivery of the manuscript a review of the language 
definition resulted in a few modifications.  This 
impacts the book as follows:

p.24 : the keyword ``handle'' is now replaced with
       the keyword ``catch'' (also page 430).

p.40 : named enumerations now define unique integral
       types.  For example,

	enum TestStatus { NOT_RUN=-1, FAIL, PASS };
	enum Boolean { FALSE, TRUE };

	main() {
    		TestStatus test = NOT_RUN;
    		Boolean found = FALSE;

    		test = -1; // error: TestStatus = int
    		test = 10; // error: TestStatus = int
    		test = found; // error: TestStatus = Boolean
    		test = FALSE; // error: TestStatus = const Boolean
    		int st = test; // ok: implicit conversion
	}

        for compatibility with prior releases, the 2.0 
        implementation issues warnings rather than errors.

p. 159: Overloaded functions can now be distinquished by
        arguments of an enumeration type.  For example,

	enum Bool { FALSE, TRUE } found;
	enum Stat { FAIL, PASS };

	extern void ff( Bool );
	extern void ff( Stat );
	extern void ff( int );

	ff( PASS );  // ff( Stat )
	ff( 0 );     // ff( int )
	ff( found ); // ff( Bool )

p. 264-265: Class instances of operator new and operator delete
        should define arguments of type ``size_t'' rather
        than of type long.  As Andy Koenig pointed out in a
        discussion of these operators, the current 2.0 
        implementation accepts the long argument and replaces
        it with that of size_t.

        The class instance of operator delete must define a
        return type of void.  (There was a brief window when
        it was permitted to define an arbitrary return type 
        -- this section was completed during this window.) 

p. 354 : A virtual function invoked within either the constructor
         OR destructor of a base class is resolved statically
         to the instance defined by the base class.  (Thanks
         to Andy Koenig for pointing out the destructor case.)

These corrections will be reflected in a subsequent reprinting
of the book.

Stan Lippman
AT&T Bell Laboratories
        

mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) (06/20/89)

[I'm sorry if the original cancelled one gets out, too.]

In article <883@kaiser.UUCP> stan@kaiser.UUCP (s Lippman) writes:
>p.40 : named enumerations now define unique integral
>       types.  For example,
>
>	enum TestStatus { NOT_RUN=-1, FAIL, PASS };
>	enum Boolean { FALSE, TRUE };
>
>	main() {
>    		TestStatus test = NOT_RUN;
>    		Boolean found = FALSE;
>
>    		test = -1; // error: TestStatus = int
>    		test = 10; // error: TestStatus = int
>    		test = found; // error: TestStatus = Boolean
>    		test = FALSE; // error: TestStatus = const Boolean
>    		int st = test; // ok: implicit conversion
>	}

I'd like to see more details on what the semantics exactly are.  The
only examples here are for assignment, but for full clarity, I need to
know the results of applying any operator to an enum operand.

What happens when I have values and operations like:
        enum_X <op> enum_X       => enum_X ?
        Y*     <op> enum_X       => Y* or error?
        int    <op> enum_X       => enum_X or error?
        type var[enum_X];        => tye var[(int) enum_X]; or error?
Any other cases I've neglected?

Suppose I want to count the number of times NOT_RUN, FAIL, and PASS
occur.  So I'd actually do something like this:
	enum TestStatus { NOT_RUN, FAIL, PASS, MAX_TEST };
        int status_count[MAX_TEST];

        for (TestStatus i = NOT_RUN; i < MAX_TEST; i++)
            status_count[i] = 0;

        enum TestStatus rc;
        while (dotest(&rc))
            status_count[rc]++;

Is this legal or not?  I'd hate to have to muck about with
        int status_count[(int) MAX_TEST]; ...
            status_count[(int) rc]++;


>    		int st = test; // ok: implicit conversion
Bleah.  Are there any other cases in C++ where
        type var = expr;
is not equivalent to
        type var;
        var = expr;
?  Are there any other possible "implicit conversions"?


>p.40 : named enumerations now define unique integral types
What's a "named enumeration"?  Is
        typedef enum {FOO, BAR} widget;
a named enumeration?  What if we have
        enum {FOO, BAR} a;
        a = 1;     // legal or no?
Why are "named" enumerations distinguished from "unnamed" ones?
--
"Let me control a planet's oxygen supply, and I don't care who makes
the laws." - GREAT CTHUHLU'S STARRY WISDOM BAND (via Roger Leroux)
 __
   \         Tim, the Bizarre and Oddly-Dressed Enchanter
    \               mcdaniel@uicsrd.csrd.uiuc.edu
    /\       mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet}
  _/  \_     {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel

ark@alice.UUCP (Andrew Koenig) (06/20/89)

In article <1304@garcon.cso.uiuc.edu>, mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) writes:

> I'd like to see more details on what the semantics exactly are.  The
> only examples here are for assignment, but for full clarity, I need to
> know the results of applying any operator to an enum operand.

Every enumerated type is a separate type.  When used in a context
that requires an integer, a value of an enumerated type is quietly
converted to an int.  Converting the other way requires a cast.

> What happens when I have values and operations like:

>         enum_X <op> enum_X       => enum_X ?

If <op> is something like `+', the result is an int.

>         Y*     <op> enum_X       => Y* or error?

The enum_X value is quietly converted to int; the result is Y*.

>         int    <op> enum_X       => enum_X or error?

The result is an int.

>         type var[enum_X];        => tye var[(int) enum_X]; or error?

The enum_X is converted to an int.

> Suppose I want to count the number of times NOT_RUN, FAIL, and PASS
> occur.  So I'd actually do something like this:
> 	enum TestStatus { NOT_RUN, FAIL, PASS, MAX_TEST };
>         int status_count[MAX_TEST];

OK so far.

>         for (TestStatus i = NOT_RUN; i < MAX_TEST; i++)
>             status_count[i] = 0;
> 
>         enum TestStatus rc;
>         while (dotest(&rc))
>             status_count[rc]++;

It's legal.  The only part of this that's questionable is the notion of
applying ++ to an enum, but I'm pretty sure that's OK even though
the corresponding use of + would require a cast to convert the
result back to enum.

> Bleah.  Are there any other cases in C++ where
>         type var = expr;
> is not equivalent to
>         type var;
>         var = expr;
> ?  Are there any other possible "implicit conversions"?

Saying

	type var = expr;

is NEVER equivalent to saying

	type var;
	var = expr;

The first case creates var and simultaneously initializes it to expr.
The second creates var, initializes it to a default value (which is
often garbage) and then obliterates that value with `expr.'  It is possible
to define types for which either of these is legal and the other is
illegal.

> >p.40 : named enumerations now define unique integral types
> What's a "named enumeration"?  Is
>         typedef enum {FOO, BAR} widget;
> a named enumeration?  What if we have
>         enum {FOO, BAR} a;
>         a = 1;     // legal or no?

No -- you need a cast to convert an integer to an enumerated type.

> Why are "named" enumerations distinguished from "unnamed" ones?

An unnamed enumeration doesn't give you a useful handle for the type
it defines.  It defines several objects (the one above defines
FOO, BAR, and a) of a nameless type.  Since the type is nameless,
it's not possible to get at it again.
-- 
				--Andrew Koenig
				  ark@europa.att.com