The link initialization rule we are looking for is [dcl.init.ref] :
A reference to type "cv1 T1 " is initialized by an expression of type "cv2 T2 " as follows:
We have cv1 T1 as int* const* and cv2 T2 as S Then we carefully consider the following sections:
If the reference is an lvalue reference and an initializer expression
- is an lvalue (but not a bitfield), and "cv1 T1" refers to "cv2 T2" or
- has a class type (that is, T2 is a class type), where T1 is not related to T2 and can be converted to an lvalue of type "cv3 T3", where "cv1 T1" is reference-compatible with "cv3 T3" (this conversion is selected by listing the applicable conversion functions ([over.match.ref]) and choosing the best one when resolving overloads),
then the link is bound to the lvalue initializer expression in the first case and to the result of the lvalue conversion in the second case (or, in any case, to the corresponding subobject of the object’s base class).
Our link is an lvalue link. The initializer expression is an lvalue, but the two types are not reference-compatible , so the first mark is not applied.
The initializer expression has a class type that is not associated with a reference, but it cannot be converted to a reference type. The reference part is important. int** is not a reference compatible with int* const* , and although the former can be converted to the latter, the result will not be lvalue - this is also necessary.
So this section does not apply, and we move on .
Otherwise, this reference must be an lvalue reference to an immutable type of const (i.e. cv1 must be const), or the reference must be an rvalue reference.
Our link does not meet any of these criteria, so the initialization is poorly formed.
The simplest version of this failure would be:
int* pi; int const*& r = pi;
We cannot go through a qualification conversion when we have an lvalue reference for a non-constant type.