VS 2010 : 2 overloads have similar conversions - c++

I don't understand what happens here
class A{};
class B : A {};
void func(A&, bool){}
void func(B&, double){}
int main(void)
{
B b;
A a;
bool bo;
double d;
func(b, bo);
}
When compiling, Visual 2010 gives me this error on line func(b, bo);
2 overloads have similar conversions
could be 'void func(B &,double)'
or 'void func(A &,bool)'
while trying to match the argument list '(B, bool)'
I don't understand why the bool parameter isn't enough to resolve the overload.
I've seen this question, and as pointed in the accepted answer, bool should prefer the bool overload. In my case, I see that first parameter isn't enough to choose the good function, but why the second parameter doesn't solve the ambiguity?

The overloading rules are a bit more complicated than you might guess. You look at each argument separately and pick the best match for that argument. Then if there is exactly one overload that provides the best match for every argument, that's the one that's called. In the example, the best match for the first argument is the second version of func, because it requires only a conversion of B to B&; the other version of func requires converting B to B& and then B& to A&. For the second argument, the first version of func is the best match, because it requires no conversions. The first version has the best match for the second argument, but it does not have the best match for the first argument, so it is not considered. Similarly, the second version has the best match for the first argument, but it does not have the best match for the second argument, so it is not considered. Now there are no versions of func left, and the call fails.

Overload resolution rules are even more complicated than Pete Becker wrote.
For each overload of f, the compiler counts not only the number of parameters for which conversion is required, but the rank of conversion.
Rank 1
No conversions required
Lvalue-to-rvalue conversion
Array-to-pointer conversion
Function-to-pointer conversion
Qualification conversion
Rank 2
Integral promotions
Floating point promotions
Rank 3
Integral conversions
Floating point conversions
Floating-integral conversions
Pointer conversions
Pointer to member conversions
Boolean conversions
Assuming that all candidates are non-template functions, a function wins if and only if it has a parameter which rank is better than the rank of the same parameter in other candidates and the ranks for the other parameters are not worse.
Now let's have a look at the OP case.
func(A&, bool): conversion B&->A& (rank 3) for the 1st parameter,
exact match (rank 1) for the 2nd parameter.
func(B&, double): exact match (rank 1) for the 1st parameter, conversion bool->double (rank 3) for the 2nd parameter.
Conclusion: noone wins.

Related

Ambiguity in Function Overloading Rules? (Exact > Promote > Convert)

#include <string>
void foo(int x, short y, int z) { std::cout << "normal int" << std::endl; } //F1
void foo(double x, int y, double z) { std::cout << "normal double" << std::endl; } //F2
int main()
{
short x = 2;
foo(5.0, x, 8.0);
}
Based on function overloading rules,
F1( Exact = 1, Promote = 0, Convert = 2 ) and
F2( Exact = 2, Promote = 1, Convert = 0 ). Shouldn't F2 be called? Why is the call ambiguous?
Overload resolution can get complicated. But here it's fairly straightforward. I'll rewrite the function prototypes to remove the third argument, since it doesn't affect the analysis.
void foo(int, short);
void foo(double, int);
double d = 1.0;
short s = 2;
f(d, s); // ambiguous
The rule is that you look at each argument, one at a time, and determine which function has the "best" conversion for that argument. If one function has the best conversion for every argument, that's the one that's called. If there's no function that's best for every argument, the call is ambiguous.
For the first argument, the type of the argument is double. Calling the first version of foo requires a conversion from double to int; calling the second version of foo requires no conversion; it's an exact match. So for the first argument, the second version of foo has the best conversion.
For the second argument, the type of the argument is short. Calling the first version of foo requires no conversion; it's an exact match. Calling the second version of foo requires a promotion from short to int. So for the second argument, the first version of foo has the best conversion.
Since the first version of foo has the best match for the second argument and the second version of foo has the best match for the first argument, there is no function with the best match on all arguments, and the call is ambiguous.
Overload resolution ranks the viable candidate functions by comparing how each argument of the call matches the corresponding parameter of the candidates. Moreover, for one candidate to be considered better than another, the better candidate cannot have any of its parameters be a worse match than the
corresponding parameter in the other candidate.
Now, let's apply this to your given example snippet.
void foo(int x, short y, int z);
void foo(double x, int y, double z) ;
int main()
{
short x = 2;
foo(5.0, x, 8.0);
}
In the above snippet, For the case of first overloaded foo, the second argument matches exactly with the type of the second parameter. But the first and third argument have type double while the corresponding parameters have type int and so the first and the third argument requires a conversion to int in this case.
On the other hand, for the case of second overloaded foo, the first and third argument matches exactly with the first and third parameter respectively. But in this case, the second argument is of type short while the second parameter is of type int. So a promotion to int is needed for the second argument.
Result 1
Now, according to the highlighted part at the beginning of my answer, for the first candidate to be considered a better match than the second candidate, none of the first candidate's parameter can be a worse match than the corresponding parameter in the second candidate. But we already discussed that the first and third parameter of first overloaded candidate are worse match than the corresponding parameters in the second overloaded candidate since they require conversion to int. Thus, the first overloaded candidate is not a better match than the second overloaded candidate.
Result 2
Similarly, for the second candidate to be considered a better match than the first candidate, none of the second candidate's parameter can be a worse match than the corresponding parameter in the first candidate. But here also we already discussed that the second parameter in the second candidate is worse match than the corresponding parameter in the first candidate since it requires a promotion. Thus, the second candidate is not a better match than the first candidate.
Conclusion
Combining both of the results above, we get to the conclusion that none of the candidates is better than the other. Hence the call is ambiguous.
The ranking of conversion sequences matters only when comparing ranking of the conversion sequences applied to the same argument.
If one argument's conversion rank is better in the first overload than in the second one and the other way around for another argument's conversion rank, then neither overload is considered better than the other and the overload resolution is ambiguous.
This applies here. The first and third argument have a better conversion rank (exact rather than conversion) in the second overload, while the second argument has a better conversion rank in the first overload (exact rather than promotion).

How is ambiguity determined in the overload resolution algorithm?

I'm trying to understand the overloading resolution method.
Why is this ambiguous:
void func(double, int, int, double) {}
void func(int, double, double, double) {}
void main()
{
func(1, 2, 3, 4);
}
but this isn't?
void func(int, int, int, double) {}
void func(int, double, double, double) {}
void main()
{
func(1, 2, 3, 4);
}
In the first case there are 2 exact parameters matches and 2 conversions against 1 exact match and 3 conversions, and in the second case there are 3 exact matches and 1 conversion against 1 exact matches and 3 conversions.
So why is one ambiguous and one is not? What is the logic here?
The overload resolution rules only define a partial order on the set of all matches - if an overload F1 is not a better match than F2, it does not imply that F2 is a better match than F1. The exact partial order can be thought of as comparing two points in k dimensions, where the number of arguments is k. Lets define this partial order on points in k-dim space - (x_1, x_2,..., x_k) < (y_1, y_2,..., y_k) if x_i <= y_i for all i and x_j < y_j for at least one j. This is exactly the partial order on candidate non-template functions defined by the standard.
Lets look at your examples :
void func(double, int, int, double) {}
vvv vvv vvv
better better equal
void func(int, double, double, double) {}
vvv vvv
better equal
So neither overload is strictly better than the other.
In your second example:
void func(int, int, int, double) {}
vvv vvv vvv vvv
equal better better equal
void func(int, double, double, double) {}
vvv
equal
Now, the first overload is better than the second in all but one argument AND is never worse than the second. Thus, there is no ambiguity - the partial order does indeed declare the first one better.
(The above description does not consider function templates. You can find more details at cppreference.)
The wording from the standard (§[over.match.best]/1) is:
[...] let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F.
[...] a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
— for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2)
In your first case, the two functions fail the first test. For the first argument, the first function (taking double) has a worse conversion sequence than the second. For the second argument, the second function has a worse conversion sequence than the first (again, the int has to be promoted to double in one case, but not the other).
Therefore, neither function passes the first rule, and the call is ambiguous.
Between the second pair of functions, every argument to the the first function has at least as good of a conversion as the matching argument to the second function. We then go on to the second rule, and find that there is at least one argument (two, as a matter of fact) for which the first function has a better conversion (identity instead of promotion) than the second.
Therefore, the first function is a better match, and will be selected.
Ambiguity is determined by the ranking:
Exact match: no conversion required, lvalue-to-rvalue conversion, qualification conversion, user-defined conversion of class type to the same class
Promotion: integral promotion, floating-point promotion
Conversion: integral conversion, floating-point conversion, floating-integral conversion, pointer conversion, pointer-to-member conversion, boolean conversion, user-defined conversion of a derived class to its base
Exact match wins vs Promotion which wins vs Conversion.
In the example:
void func(int, bool, float, int){cout << "int,bool,float,int" << endl;}
void func(int, bool, int, int){cout << "int,int,int,int" << endl;}
int main()
{
func(1,1,3.4,4);
}
Argument 1(1) is an exact match on both
Argument 2(1) is an exact match on both
Argument 3(3.4) can be converted into float and int - Ambiguity Neither is better.
Argument 4(4) is an exact match on both
But if we did this: func(1,1,3.4f,4); (3.4f) is now an exact match!
void func(int, bool, float, int) then wins the battle.

Unexpectedly ambiguous overload resolution in VC++ 2012

Visual C++ 2012. Code. I think it should compile; the compiler respectfully disagrees. I've narrowed my repro down to:
struct B { };
void foo(B* b, signed int si) { } // Overload 1
void foo(B const* b, unsigned int ui) { } // Overload 2
int main()
{
B b;
unsigned int ui;
foo(&b, ui);
}
So we've got two candidates for overload resolution. For the first overload, the first argument exactly matches, and the second argument requires an integral conversion (unsigned to signed). For the second overload, the second argument exactly matches, and the first argument requires a cv-adjustment (because &b is a pointer to non-const).
Now, it seems that this should be entirely unambiguous. For Overload 1, the first argument is an "Exact Match" as defined by the standard's section on overload resolution, but the second is a "Conversion". For Overload 2, both arguments are "Exact Matches" (qualification conversion being at the same rank as identity). Therefore (my apparently imperfect reasoning goes), Overload 2 should be chosen, with no ambiguity. And yet:
a.cpp(12): error C2666: 'foo' : 2 overloads have similar conversions
a.cpp(6): could be 'void foo(const B *,unsigned int)'
a.cpp(5): or 'void foo(B *,int)'
while trying to match the argument list '(B *, unsigned int)'
note: qualification adjustment (const/volatile) may be causing the ambiguity
GCC seems fine with the code, both in default dialect and in C++11 (thanks, IDEOne!). So I'm kiiiiind of inclined to chalk this up to a bug in MSVC, but (a) you know what they say about people who think their bugs are compiler bugs, and (b) this seems like it would be a pretty obvious bug, the sort that would have sent up red flags during their conformance testing.
Is this a noncompliant MSVC, or a noncompliant GCC? (Or both?) Is my reasoning regarding the overload resolution sound?
MSVC is correct.
gcc 4.9.0 says:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
clang 3.4.1 agrees that the two functions are ambiguous.
Although B* => B* and B* => B const* both have Exact Match rank, the former is still a better conversion sequence per over.ics.rank/3; this is (per example) to ensure that:
int f(const int *);
int f(int *);
int i;
int j = f(&i); // calls f(int*)
From over.ics.rank/3:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if [...]
— S1 and S2 differ only in their qualification conversion and yield similar types T1 and T2 (4.4), respectively, and the cv-qualification signature of type T1 is a proper subset of the cv-qualification signature of type T2. [...]
And, of course, unsigned int => unsigned int is better than unsigned int => signed int. So of the two overloads, one has a better implicit conversion sequence on the first argument, and the other has a better implicit conversion sequence on the second argument. So they cannot be distinguished per over.match.best/1.

How come an user defined conversion is a better match than a standard integer conversion?

You can find the text below in Appendix B of the book "C++ Templates The Complete Guide" by David Vandevoorde and Nicolai Josuttis.
B.2 Simplified Overload Resolution
Given this first principle, we are left with specifying how well a
given argument matches the corresponding parameter of a viable
candidate. As a first approximation we can rank the possible matches
as follows (from best to worst):
Perfect match. The parameter has the type of the expression, or it has a type that is a reference to the type of the expression (possibly
with added const and/or volatile qualifiers).
Match with minor adjustments. This includes, for example, the decay of an array variable to a pointer to its first element, or the
addition of const to match an argument of type int** to a parameter of
type int const* const*.
Match with promotion. Promotion is a kind of implicit conversion that includes the conversion of small integral types (such as bool,
char, short, and sometimes enumerations) to int, unsigned int, long or
unsigned long, and the conversion of float to double.
Match with standard conversions only. This includes any sort of standard conversion (such as int to float) but excludes the implicit
call to a conversion operator or a converting constructor.
Match with user-defined conversions. This allows any kind of implicit conversion.
Match with ellipsis. An ellipsis parameter can match almost any type (but non-POD class types result in undefined behavior).
A few pages later the book shows the following example and text (emphasis mine):
class BadString {
public:
BadString(char const*);
...
// character access through subscripting:
char& operator[] (size_t); // (1)
char const& operator[] (size_t) const;
// implicit conversion to null-terminated byte string:
operator char* (); // (2)
operator char const* ();
...
};
int main()
{
BadString str("correkt");
str[5] = 'c'; // possibly an overload resolution ambiguity!
}
At first, nothing seems ambiguous about the expression str[5]. The
subscript operator at (1) seems like a perfect match. However, it is
not quite perfect because the argument 5 has type int, and the
operator expects an unsigned integer type (size_t and std::size_t
usually have type unsigned int or unsigned long, but never type int).
Still, a simple standard integer conversion makes (1) easily viable.
However, there is another viable candidate: the built-in subscript
operator. Indeed, if we apply the implicit conversion operator to str
(which is the implicit member function argument), we obtain a pointer
type, and now the built-in subscript operator applies. This built-in
operator takes an argument of type ptrdiff_t, which on many platforms
is equivalent to int and therefore is a perfect match for the argument
5. So even though the built-in subscript operator is a poor match (by user-defined conversion) for the implied argument, it is a better
match than the operator defined at (1) for the actual subscript! Hence
the potential ambiguity.
Note that the first list is Simplified Overload Resolution.
To remove the "possibly" and "potential" about whether or not int is the same as ptrdiff_t, let's change one line:
str[(ptrdiff_t)5] = 'c'; // definitely an overload resolution ambiguity!
Now the message I get from g++ is:
warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second: [enabled by default]
and --pedantic-errors promotes that warning to an error.
So without diving into the standard, this tells you that the simplified list is only part of the story. That list tells you which of several possible routes to prefer when going from A to B, but it does not tell you whether to prefer a trip from A to B over a trip from C to D.
You can see the same phenomenon (and the same g++ message) more obviously here:
struct S {
explicit S(int) {}
operator int() { return 0; }
};
void foo(const S&, long) { }
void foo(int, int) { }
int main() {
S s(0);
foo(s, 1);
}
Again the call to foo is ambiguous, because when we have a choice of which argument to implicitly convert in order to choose an overload, the rules don't say, "pick the more lightweight conversion of the two and convert the argument requiring that conversion".
Now you're going to ask me for the standard citation, but I shall use the fact I need to hit the hay as an excuse for not looking it up ;-)
In summary it is not true here that "a user defined conversion is a better match than a standard integer conversion". However in this case the two possible overloads are defined by the standard to be equally good and hence the call is ambiguous.
str.operator[](size_t(5));
Write code in definite way and you'll not need to bother about all this stuff :)
There is much more to thing about.

Why is variable automatically being passed by reference?

I'm attempting to call a function in the ROOT plotting package that accepts three variables. The relevant section in my code is:
int xwidth=0,ywidth=0;
Bool_t useangle=0;
vIt->GetBoundingBox(xwidth,ywidth,useangle);
where vIt is an iterator to an object with GetBoundingBox as a class member function. (Bool_t is just a typedef that ROOT uses).
Now, when I compile, I get the following error from g++:
error: no matching function for call to ‘TText::GetBoundingBox(int&, int&, Bool_t&)’
/home/bwhelan/Programs/MODIFIED//External/root/5.30.00/include/root/TText.h:57: note: candidates are: virtual void TText::GetBoundingBox(UInt_t&, UInt_t&, Bool_t)
My question is why is useangle being passed by reference here, instead of by value? I simply cannot figure it out.
In C++, upon overload resolution, a set of viable overloads is selected, and the one candidate that requires the least
conversions (does it require changing the constness? is a promotion of integer to floating point needed?)
is chosen. If there are multiple matches that have the same weight, you have an ambiguous call and get an error
(e.g.: int foo(int &x, int y); int foo(int x, int &y); ... int a,b; foo(a,b); is ambiguous).
However, in your case, no valid conversion sequence can be found, because there exists no valid conversion from
int& to unsigned int& (sidenote: there exists a conversion from int to unsigned int and vice versa), because
references to unrelated types are not compatible at all.
About the error message: The compiler uses the weakest allowed binding to filter out the set of viable functions. For int, this is int&.
But because no viable set of functions is found, an error message is spit out. The author of the message did not base
it on your code, but rather on the data he/she has had for the search, which is int&. However, he/she
correctly proposes a viable alternative that really exists.
So we have more a compiler diagnostic quality issue here, rather than a C++ correctness issue.
From the standard, here's the table of conversion. The least are required to make a function call
valid, the better the match:
Conversion
-----------------------------------+----------------------------
No conversions required | Identity
-----------------------------------+----------------------------
Lvalue-to-rvalue conversion | Lvalue transformation
Array-to-pointer conversion |
Function-to-pointer conversion |
-----------------------------------+----------------------------
Qualification conversions | Qualification adjustment
-----------------------------------+----------------------------
Integral promotions | Promotion
Floating point promotion |
-----------------------------------+----------------------------
Integral conversions | Conversion
Floating point conversions |
Floating-integral conversions |
Pointer conversions |
Pointer to member conversions |
Boolean conversions |
-----------------------------------+----------------------------
The problem isn't that the bool is passed by reference but that you line
int xwidth=0,ywidth=0;
Should be of type UInt_t
UInt_t xwidth=0u,ywidth=0u;
The compiler doesn't know how you want to pass the variable to function with the unkown overload so it just assumes you meant by ref.
The signature of the function have the following arguments
UInt_t&, UInt_t&, Bool_t
and you are passing
int&, int&, Bool_t&
Either convert your int to UInt_t before you call the method or directly declare them as UInt_t.
It is not.
Compiler messages are more or less useful. As it is, since it did not find a method that it can call with the arguments you supplied, the compiler is trying to synthetize, from the arguments you gave, a method signature that could have worked.
This is, unfortunately, ultimately doomed to fail, as there are just so many possible variations, but then gcc's messages have never been too great.
Clang took another approach, which I happen to prefer. Instead of trying to imagine what the function you wanted to call looks like and then listing the candidates and leaving you to spot the differences, it tells you why each candidate was discarded.
void func(unsigned&, unsigned&);
int something() {
int a = 0, b = 0;
func(a, b);
return a + b;
}
Yields the following error message:
/tmp/webcompile/_3246_0.cc:5:3: error: no matching function for call to 'func'
func(a, b);
^~~~
/tmp/webcompile/_3246_0.cc:1:6: note: candidate function not viable:
no known conversion from 'int' to 'unsigned int &' for 1st argument;
void func(unsigned&, unsigned&);
Which I find much more useful. Patching this by turning a into an unsigned and leaving b as is we get:
/tmp/webcompile/_3710_0.cc:1:6: note: candidate function not viable:
no known conversion from 'int' to 'unsigned int &' for 2nd argument;
void func(unsigned&, unsigned&);
And this way we advance one argument at a time until we "fixed" the call to our liking.