#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