How to compare two standard conversion sequences use the rank of contained conversions

会有一股神秘感。 提交于 2021-02-07 12:45:15

问题


#include <iostream>
void g(int*);  //#1
void g(int (&arr)[2]);  //#2

void f(int*);  //#3
void f(int const*);  //#4
int main(){
  int arr[2] ={0};
  f(arr);    // choose #3
  g(arr);  //ambiguous
}

Consider the above code, #3 is seleteced for f(ptr), however, g(arr) gives a ambiguous diagnostic.

The rule for choosing the best function is defined as:

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

  • S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by [over.ics.scs], excluding any Lvalue Transformation; the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence) or, if not that

So take a look at over.ics.scs#3

These are used to rank standard conversion sequences. The rank of a conversion sequence is determined by considering the rank of each conversion in the sequence and the rank of any reference binding.

According to my understanding of the above rule, I can understand why #3 is the best overload for f(ptr), that is:

Given S1 as (arr => int*):

Array-to-pointer conversion -> (identity conversion)  
^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^                   
     int[2] => int*             int* => int* 

while given S2 as (ptr => int const*)

Array-to-pointer conversion -> Qualification conversions ->  identity conversion   
^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^^^^^^^     ^^^^^^^^^^^^^^^^^^^ 
     int[2] => int*               int* => int const*           int const* => int const* 

Since identity conversion is a proper subsequence of Qualification conversions, hence S1 is better than S2. So, #3 is selected by overload resolution for f(ptr).

When I use a similar process to determine which is best for g(arr), I encounter an issue.

Again, given S1 as (arr => int*)

Array-to-pointer conversion -> identity conversion  
^^^^^^^^^^^^^^^^^^^^^^^^^^^    ^^^^^^^^^^^^^^^^^^^ 
      int[2] => int*              int* => int*

while given S2 as(arr => int (&arr)[2])

When a parameter of reference type binds directly to an argument expression, the implicit conversion sequence is the identity conversion, unless the argument expression has a type that is a derived class of the parameter type, in which case the implicit conversion sequence is a derived-to-base Conversion

identity conversion
^^^^^^^^^^^^^^^^^^^
  bind to reference   

Here, identity conversion of S2 is a proper subsequence of Array-to-pointer conversion of S1, hence it should be better than S1, why the compiler complained g(arr) is an ambiguous invocation?

Do I have any misreading about how to rank the standard conversion sequences? How to compare two standard ICS (rank of the contained conversion)?


回答1:


The key point is here:

S1 is a proper subsequence of S2 (comparing the conversion sequences in the canonical form defined by [over.ics.scs], excluding any Lvalue Transformation; the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence) or, if not that

That means, for function call g(arr), all Array-to-pointer conversion are not used to determine the rank. In other words, from type int[2] to type int*, there's only an identity conversion that used to determine the rank. Hence, S1 of void g(int*); and S2 of void g(int (&arr)[2]); are indistinguishable ICS, hence the compiler gives an ambiguous error.

As a contrast, the conversions for void f(int*); and void f(int const*); used to compare rank are identity conversion and qualification conversion, respectively.

According to the rule:

the identity conversion sequence is considered to be a subsequence of any non-identity conversion sequence

Hence, Qualification conversion is considered to have a worse rank than that of identity conversion. So, void f(int*) wined the competition.




回答2:


You are trying to apply over.ics.rank-3.2.1 to these overload sets, but this rule doesn't apply for either f or g.


Given the call f(arr);, when performing overload resolution for f, both overloads require a standard conversion sequence consisting of an Array-to-pointer conversion, and both have the same rank, which is Exact Match. The tie breaker used in this case is over.match.best#over.ics.rank-3.2.5:

Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if

...

S1 and S2 differ only in their qualification conversion ([conv.qual]) and yield similar types T1 and T2, respectively, where T1 can be converted to T2 by a qualification conversion.

There's an example following this rule that demonstrates how the rule works.

For the overload set f, T1 is int * and T2 is int const *, and T1 can be converted to T2 by a qualification conversion.


In the case of the call g(arr);, when performing overload resolution, the overload g(int (&)[2]) is ranked as an Exact match, since the standard conversion sequence needed is a No Conversion Required.

However, the overload g(int*) is also ranked as an Exact match, since the standard conversion sequence needed is an Array-to-Pointer conversion.

Unlike for f however, there is no rule in [over.ics.rank] that disambiguates between the standard conversion sequences for g, and the call fails.



来源:https://stackoverflow.com/questions/65247901/how-to-compare-two-standard-conversion-sequences-use-the-rank-of-contained-conve

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!