typedef question

J

John

I thought I had a fairly good understanding of typedefs until I came across
the following passage from C++ Primer, fourth edition by Stanley B. Lippman:

"The mistake is in thinking of a typedef as a textual expansion" (page 129).

All of my other C++ books and every mention of typedefs that I've seen on the
Internet simply call typedefs a new name as an alias for a type, e.g.

typedef char byte ; // make byte an alias for char (from C++ Primer Plus, 5th
edition by Stephen Prata).

Then I came across this in Lippman's book (also on page 129):

----------------------
typedef string *pstring ;
const pstring cstr ;

What is the type of cstr?

Many think that the actual type is

const string *cstr ; // wrong

The definition is equivalent to

string *const cstr ;
 
H

Howard

John said:
I thought I had a fairly good understanding of typedefs until I came across
the following passage from C++ Primer, fourth edition by Stanley B.
Lippman:

"The mistake is in thinking of a typedef as a textual expansion" (page
129).

All of my other C++ books and every mention of typedefs that I've seen on
the Internet simply call typedefs a new name as an alias for a type, e.g.

typedef char byte ; // make byte an alias for char (from C++ Primer Plus,
5th edition by Stephen Prata).

Then I came across this in Lippman's book (also on page 129):

----------------------
typedef string *pstring ;
const pstring cstr ;

What is the type of cstr?

Many think that the actual type is

const string *cstr ; // wrong

The definition is equivalent to

string *const cstr ;
----------------------

No matter how many times I read the explanation in Lippman's book, I'm
still lost. Since typedefs are clearly not simple aliases as all of the
other books claim, I'm hoping that someone could help me understand the
above .

Try mentally using parentheses to help. The definition

const (pstring) cstr;

would "expand" into

const (string *) cstr;

which would be equivalent to:

(string *) const cstr;

This means that what is const is the (string *), which means it is a const
pointer, not a pointer to a const string. Now, removing those
mentally-placed parentheses...

A const pointer (to string) is written as

string * const cast; // const pointer-to-string

Not

const string * cstr; // pointer to const string

or its equivalent:

string const * cstr; // pointer to const string

-Howard
 
A

Alan Johnson

John said:
I thought I had a fairly good understanding of typedefs until I came across
the following passage from C++ Primer, fourth edition by Stanley B. Lippman:

"The mistake is in thinking of a typedef as a textual expansion" (page 129).

All of my other C++ books and every mention of typedefs that I've seen on the
Internet simply call typedefs a new name as an alias for a type, e.g.

typedef char byte ; // make byte an alias for char (from C++ Primer Plus, 5th
edition by Stephen Prata).

Then I came across this in Lippman's book (also on page 129):

----------------------
typedef string *pstring ;
const pstring cstr ;

What is the type of cstr?

Many think that the actual type is

const string *cstr ; // wrong

The definition is equivalent to

string *const cstr ;
----------------------

No matter how many times I read the explanation in Lippman's book, I'm still
lost. Since typedefs are clearly not simple aliases as all of the other
books claim, I'm hoping that someone could help me understand the above .

The solution lies in understanding the difference between a:
1: pointer to a constant string. i.e. const string * - or -
string const * (equivalent)
2: constant pointer to a string. i.e. string * const

In (1), the string is constant, but the pointer is not. You can change
the pointer as much as you
want, as long as you don't change the thing it points to. That is:
const string * p ;
const string x ;
const string y ;

p = &x ; // Fine, p is not const.
p = &y ; // Fine, p is not const.
(*p) = "blah" ; // ERROR! The string p is pointing to IS const.

In (2), the pointer is const, but not the string. That is:
string x ;
string y ;
string * const p = &x ;

(*p) = "blah" ; // Fine. The string p points to is not const.
p = &y ; // ERROR! p is const.


Okay, so now that you understand the difference, let's go back to the
typedef:
typedef string * pstr ;

This makes a type called pstr which is a pointer to a string. Adding
"const" in front of a type makes that type constant, so "const pstr"
would be a constant pointer to a string, or (2) above. If, however, you
considered a typedef as a text replacement, then "const pstr" would
expand to "const string *", which is the syntax for declaring a pointer
to a constant string, or (1) above.
 
F

Frederick Gotham

John posted:
typedef char byte ; // make byte an alias for char


Indeed. The syntax is conveniently identical to the definition of an object
or function:

char (*byte(int))[50];

"byte" is a function which returns a pointer to an array of fifty char's.

typedef char (*byte(int))[50];

"byte" is the type of a function which returns a pointer to an array of
fifty char's.

typedef string *pstring ;


Well, if we were defining an object, the type of "pstring" would be:

string*

That is: Non-const pointer to non-const string. If we had a "nonconst"
keyword, we could write it as:

string nonconst *nonconst
or:
nonconst string *nonconst

const pstring cstr ;


Here we have a const pstring. The type of "cstr" is:

string *const

No matter how many times I read the explanation in Lippman's book, I'm
still lost. Since typedefs are clearly not simple aliases as all of the
other books claim, I'm hoping that someone could help me understand the
above.


If you have a definition which is "simple" (i.e. not a pointer, not an
array, not a reference, not a function), then you define it as follows:

int i;

If you want the object to be const, then you write "const" either before or
after the type:

int const i;
const int i;

If you want a more "complicated" definition, then things become different.
You start off with the fundamental type, which includes the constness and
volatility, for example:

int const

, next you write its name:

int const i;

Now, here's where things get special. Having already specified the
"fundamental type", the way you specify more information for a "special
definition" is by messing with the name. For instance, let's turn it into a
pointer:

int const *p;

From now, the "int const" doesn't apply to "p" at all, because we're
dealing with a special definition -- the "int const" simply specifies the
"fundamental type". At the moment, "p" is non-const. If we want to make it
const, we mess with the name again:

int const *const p;

(You can think of its name as being "*const p".)

The whole idea of an object's name having an effect on its type is
reflected in the following multiple definition:

int *p, *q, r[5], (*s)[5], *t[5], Func(), *Func2();

p is a pointer.
q is a pointer.
r is an array of five.
s is a pointer to an array of five.
t is an array of five pointers.
Func is a function which returns an int.
Func2 is a function which returns a pointer to an int.

A typedef doesn't do simple text replacement -- if you want that, then use
#define. Instead, it gives another name for a fully-fledged fundamental
type. A fundamental type includes "constness" and "volatility".

Looking at that object definition again:

const pstring cstr;

We see that the fundamental type is "pstring". We know that a "pstring" is
a non-const pointer to a non-const string.

When defining an object, you can place the "const" before or after the
fundamental type, so the following two are equivalent:

const pstring cstr;
pstring const cstr;

So you see: Once you make a typedef, you've made a full-fledged fundamental
type which can't be hacked at.

(I hope I explained that OK. It's one of those things that experienced
programmers simply just understand and accept, but which is hard to get
across to beginners.)
 
J

John

Frederick said:
John posted:
typedef char byte ; // make byte an alias for char


Indeed. The syntax is conveniently identical to the definition of an object
or function:

char (*byte(int))[50];

"byte" is a function which returns a pointer to an array of fifty char's.

typedef char (*byte(int))[50];

"byte" is the type of a function which returns a pointer to an array of
fifty char's.

typedef string *pstring ;


Well, if we were defining an object, the type of "pstring" would be:

string*

That is: Non-const pointer to non-const string. If we had a "nonconst"
keyword, we could write it as:

string nonconst *nonconst
or:
nonconst string *nonconst

const pstring cstr ;


Here we have a const pstring. The type of "cstr" is:

string *const

No matter how many times I read the explanation in Lippman's book, I'm
still lost. Since typedefs are clearly not simple aliases as all of the
other books claim, I'm hoping that someone could help me understand the
above.


If you have a definition which is "simple" (i.e. not a pointer, not an
array, not a reference, not a function), then you define it as follows:

int i;

If you want the object to be const, then you write "const" either before or
after the type:

int const i;
const int i;

If you want a more "complicated" definition, then things become different.
You start off with the fundamental type, which includes the constness and
volatility, for example:

int const

, next you write its name:

int const i;

Now, here's where things get special. Having already specified the
"fundamental type", the way you specify more information for a "special
definition" is by messing with the name. For instance, let's turn it into a
pointer:

int const *p;

From now, the "int const" doesn't apply to "p" at all, because we're
dealing with a special definition -- the "int const" simply specifies the
"fundamental type". At the moment, "p" is non-const. If we want to make it
const, we mess with the name again:

int const *const p;

(You can think of its name as being "*const p".)

The whole idea of an object's name having an effect on its type is
reflected in the following multiple definition:

int *p, *q, r[5], (*s)[5], *t[5], Func(), *Func2();

p is a pointer.
q is a pointer.
r is an array of five.
s is a pointer to an array of five.
t is an array of five pointers.
Func is a function which returns an int.
Func2 is a function which returns a pointer to an int.

A typedef doesn't do simple text replacement -- if you want that, then use
#define. Instead, it gives another name for a fully-fledged fundamental
type. A fundamental type includes "constness" and "volatility".

Looking at that object definition again:

const pstring cstr;

We see that the fundamental type is "pstring". We know that a "pstring" is
a non-const pointer to a non-const string.

When defining an object, you can place the "const" before or after the
fundamental type, so the following two are equivalent:

const pstring cstr;
pstring const cstr;

So you see: Once you make a typedef, you've made a full-fledged fundamental
type which can't be hacked at.

(I hope I explained that OK. It's one of those things that experienced
programmers simply just understand and accept, but which is hard to get
across to beginners.)

Thank you very much (and to the other folks) for helping me understand.

I'm not a beginner; I've been reading C++ books for a whole 2 weeks :cool:
 
F

Frederick Gotham

John posted:
Thank you very much (and to the other folks) for helping me understand.

I'm not a beginner; I've been reading C++ books for a whole 2 weeks :cool:


You'll learn a massive amount by asking question here; keep it up.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top