Reference-to-reference types (like T & &
) do not exist in C++.
Where T
is an object type (which includes int
, as in your example):
(Similarly, cv-qualified types like const T&
exist, while types like const T & &
do not exist.)
You asked for an example. Consider this wrong code:
int main()
{
int ival = 1024;
int &refVal = ival;
int & &refRefVal = refVal; // wrong
}
This is an error because there is no such type as int & &
. It would be an error regardless of what I tried to initialize it with.
(Strictly speaking, it is an error because the syntax of the language prohibits it. The standards committee could have chosen to allow me to write int & &
and have it mean the same thing as int &
--see Reference Collapsing below--but they didn't, which is good, because that would be very confusing.)
When I attempt to compile that wrong code with Clang 3.8, I get:
error: 'refRefVal' declared as a reference to a reference
Other compilers give similar errors. For example, Microsoft Visual C++ gives:
error C2529: 'refRefVal': reference to reference is illegal
When you use a reference, the effect is to use the object it refers to.
References are dereferenced automatically in most contexts where they appear. Anything you try to do to a reference, really you are doing it to the object it refers to. Unlike pointers, there is no operator for dereferencing a reference; in effect the reference is a name for the referenced object.
What you have written (int &refVal3 = refVal;
) is not an error, because you are simply initializing a second reference bound to the same object. To see why this is, consider the effect of several of your statements.
Here you create an int
, initializing it with the value 1024
:
int ival = 1024;
Here you make an lvalue reference, bound to that int
object:
int &refVal = ival;
Here you assign 2
to the original int
object, because refVal
is used as the object to which it refers:
refVal = 2;
Here you create a second int
object, initialized with the value of the original object, also because refVal
is used as the object to which it refers:
int ii = refVal;
Here you make a second lvalue reference to the original object, also because refVal
is used as the object to which it refers:
int &refVal3 = refVal;
Code that looks like it creates a second reference to the first one is, therefore, really creating a second reference to the original object.
This is to say that the reason int &refVal3 = refVal;
introduces another reference to the original object--rather than attempting to create a reference to a reference--is that this is just another consequence of refVal
being automatically taken to mean the int
it refers to.
Reference Collapsing
You can't write types named like T & &
yourself, but what about this?
using Ref = int&;
using RefRef = Ref&; // I named this poorly, it's not really a reference to a reference!
This causes the compiler to see that I am trying to make a type alias RefRef
to be int& &
. The compiler follows the rules of reference collapsing. It collapses the two references into one, so the effect is the same as if I had written:
using RefRef = int&;
This behavior is useful in situations that involve type deduction, such as with templates, both by allowing more code to compile and work as expected than otherwise would, and by facilitating perfect forwarding. (One might argue it also parallels what you observed--when you initialize references from references, you can still never get a reference to a reference, only to an object.)
In no case is there ever anything whose type is reference to reference. The C++ language simply does not have any such types.