#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)?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With