Reputation: 108
I have a question regarding the c++ function matching for parameters of types T
and const T&
.
Let's say I have the following two functions:
void f(int i) {}
void f(const int &ri) {}
If I call f
with an argument of type const int
then this call is of course ambiguous. But why is a call of f
with an argument of type int
also ambiguous? Wouldn't be the first version of f
be an exact match and the second one a worse match, because the int
argument must be converted to a const int
?
const int ci = 0;
int i = 0;
f(ci); // of course ambiguous
f(i); // why also ambiguous?
I know that such kind of overloading doesn't make much sense, because calls of f
are almost always ambiguous unless the parameter type T doesn't have an accessible copy constructor. But I'm just studying the rules of function matching.
Regards, Kevin
EDIT: To make my question more clear. If I have the two functions:
void f(int *pi) {}
void f(const int *pi) {}
Then the following call is not ambiguous:
int i = 0;
f(&i); // not ambiguous, first version f(int*) chosen
Although both versions of f
could be called with &i
the first version is chosen, because the second version of f
would include a conversion to const.
That is, the first version is a "better match". But in the two functions:
void f(int i) {} and
void f(const int &ri) {}
This additional conversion to const
seems to be ignored for some reason. Again both versions of f
could be called with an int
. But again, the second version of f
would require a conversion to const
which would make it a worse match than the first version f(int).
int i = 1;
// f(int) requires no conversion
// f(const int &) does require a const conversion
// so why are both versions treated as "equally good" matches?
// isnt this analogous to the f(int*) and f(const int*) example?
f(i); // why ambiguous this time?
Upvotes: 4
Views: 1112
Reputation: 283733
One call involves an "lvalue-to-rvalue conversion", the other requires an identity conversion (for references) or a "qualification adjustment" (for pointers), and according to the Standard these are treated equally when it comes to overload resolution.
So, neither is better on the basis of differing conversions.
There is, however, a special rule in the Standard, section 13.3.3.2, that applies only if both candidates being compared take the parameter by reference.
Standard conversion sequence
S1
is a better conversion sequence than standard conversion sequenceS2
if ...S1
andS2
are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized byS2
refers is more cv-qualified than the type to which the reference initialized byS1
refers.
There's an identical rule for pointers.
Therefore the compiler will prefer
f(int*);
f(int&);
over
f(const int*);
f(const int&);
respectively, but there's no preference for f(int)
vs f(const int)
vs f(const int&)
, because lvalue-to-rvalue transformation and qualification adjustment are both considered "Exact Match".
Also relevant, from section 13.3.3.1.4:
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.
Upvotes: 4
Reputation: 168
The reason the second call f(i) is ambiguous is because to the compiler, both functions would be acceptable. const-ness can't be used to overload functions because different const versions of functions can be used in a single cause. So in your example:
int i = 0;
fi(i);
How would the compiler know which function you intended in invoking? The const qualifier is only relevant to the function definition.
See const function overloading for a more detailed explanation.
Upvotes: 0
Reputation: 5325
The second call f(i)
is also ambiguous because void f(const int &ri)
indicates that ri
is a reference to i
and is a constant. Meaning it says that it will not modify the original i
which is passed to that function.
The choice whether to modify the passed argument or not is in the hands of the implementer of the function not the client programmer who mearly uses that function.
Upvotes: 1