Why is this reference binding poorly formed?

Consider this code:

int **p = 0; class S { public: explicit operator int**&() { return p; } }; int main() { S a; int *const*&b (a); // error in both g++-7 and clang-5.0 with "-std=c++17" return 0; } 

You will agree

  • qualification conversion from int** to int*const* possible, and
  • int *const*&b (a) is direct initialization.

First, we refer to 11.6.3, paragraph 5 [dcl.init.ref] of n4700 .

A reference to the type "cv1 T1 (= int*const*) " is initialized by an expression of the type "cv2 T2 (= S) " as follows:

  • If the reference is an lvalue reference and an initializer expression
    • ...
    • has a class type (i.e., T2 is a class type), where T1 does not refer to T2 and can be converted to a value of type l of type “cv3 T3 ”, where “cv1 T1 ” refers to “cv3 T3 ” (this conversion is selected , listing the applicable conversion functions (16.3.1.6) and choosing the best one when resolving overload (16.3)),

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 ...

Here we expect T3 be int*const* . As indicated above, regardless of whether this possible conversion is determined according to clause 1 of section 16.3.1.6 [over.match.ref].

... Assuming that the "cv1 T reference" is the type of the link being initialized, and "cv S " is the type of the initializer expression, with the S type of the class, candidate functions are selected as follows:

  • ... For direct initialization, those explicit conversion functions that do not hide inside S and produce the type "lvalue reference to cv2 T2 " or "cv2 T2 " or "rvalue reference to cv2 T2 ", respectively, where T2 is the same type as and T or can be converted to type T with qualification conversion are also candidate functions .

Here S::operator int**& displays the link "lvalue to T2 (= int**) " and can be converted to T (= int*const*) by qualification conversion. Here we can say that conversion is possible, but the program is not accepted in both g ++ - 7 and clang-5.0. Why is this?

+5
source share
1 answer

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; // error 

We cannot go through a qualification conversion when we have an lvalue reference for a non-constant type.

+7
source

Source: https://habr.com/ru/post/1274349/


All Articles