I thought &
and *
were just semantical conventions to declare pointers and references, but when trying to declare a reference to a int pointer I have to use int*&
otherwise it errors out to error: cannot declare pointer to ‘int&’
They are more than conventions; they are rules of the C++ language.
Furthermore why is it that we use int* to declare integer pointers instead of int& and vice versa for references?
Fundamentally, there is no reason why we must use one character versus another to denote any particular concept. We could designate *
to stand for addition and }
to stand for an elephant. As it happens, *
was chosen to use for pointers when C was being developed. I expect it was chosen largely on the basis of what characters were available in the character sets and keyboards in use at the time, as well as what other characters had been assigned other meanings. Possibly .
could have been used for a pointer. However *
was chosen.
When C++ was developed, &
was likely chosen to use for references because it was already associated with addresses due to its use in C for taking the address of an object or function.
So, that is how we ended up with *
and &
for pointers and references.
Next, why we write int *&
for a reference to a pointer arises from how the grammar of declarations was designed. As Kernighan and Ritchie told us in The C Programming Language, a declaration shows a sort of picture of how an identifier will be used. int *x
means *x
will be used as an int
, and therefore x
must be a pointer to an int
.
The *x
part of int *x
is called the declarator. A declarator can be complicated, as in int *(*x)[3]
, which declares a pointer to an array of 3 pointers to int
. Because of the notion of the declarator giving us a picture of how the identifier will be used, the declarator gives us the final type of the pictured expression, so we must unwind the declarator—parse it in reverse in a sense—to figure out what the type of the declared identifier is.
In C++, &
for references was tacked onto this existing grammatical structure. So, even if we would not write *&x
in an expression, we still parse it using the same logic. So &
binds more tightly to x
. So int *&x
tells us that *&x
is an int
, so &x
is a pointer to an int
, so x
is a reference to a pointer to an int
.
If we wrote int &*x
, that would mean that &*x
is an int
, so *x
is a reference to an int
, so x
is a pointer to a reference to an int
. However, C++ does not define pointers to references. Grammatically, we can understand what this declaration is telling us, but the type it is telling us that x
is is not defined by the C++ standard, so the compiler complains about it.