views:

1665

answers:

3

Hi All,

Can you tell me why the following code is giving me the following error - call of overloaded "C(int)" is ambiguous

I would think that since C(char x) is private, only the C(float) ctor is visible from outside and that should be called by converting int to float.

But that's not the case.

class C
{
    C(char  x)
    {
    }
public:
    C(float t)
    {
    }
};

int main()
{
    C p(0);
}
+15  A: 

This is discussed in "Effective C++" by Scott Meyer. The reason this is ambiguous is that they wanted to ensure that merely changing the visibility of a member wouldn't change the meaning of already-existing code elsewhere.

Otherwise, suppose your C class was in a header somewhere. If you had a private C(int) member, the code you present would call C(float). If, for some reason, the C(int) member was made public, the old code would suddenly call that member, even though neither the old code, nor the function it called had changed.

EDIT: More reasons:

Even worse, suppose you had the following 2 functions:

C A::foo() 
{
    return C(1.0);
}

C B::bar() 
{
    return C(1.0);
}

These two functions could call different functions depending on whether either foo or bar was declared as a friend of C, or whether A or B inherits from it. Having identical code call different functions is scary.

(That's probably not as well put as Scott Meyer's discussion, but that's the idea.)

Jesse Rusak
Hmm, this seemed like a great explanation at first. But... it's still possible to create the class _without_ an int-ctor, then later _add_ that ctor so old code suddenly starts calling the new member... So this protection only creates a false sense of security.
Good point. I'll add more.
Jesse Rusak
+7  A: 

0 is an int type. Because it can be implicitly cast to either a float or char equally, the call is ambiguous. Visibility is irrelevant for these purposes.

Either put 0.0, 0., or 0.0f, or get rid of the C(char) constructor entirely.

Edit: Relevant portion of the standard, section 13.3:

3) [...] But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:

  • First, a subset of the candidate functions—those that have the proper number of arguments and meet certain other conditions—is selected to form a set of viable functions (13.3.2).
  • Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.

4) If a best viable function exists and is unique, overload resolution succeeds and produces it as the result. Otherwise overload resolution fails and the invocation is ill-formed. When overload resolution succeeds, and the best viable function is not accessible (clause 11) in the context in which it is used, the program is ill-formed.

Note that visibility is not part of the selection process.

greyfade
You did not address why privateness doesn't tilt the overload resolution.
+1 this is half the story, but doesn't address the visibility
Jesse Rusak
Changing down to upvote for standard citation.
Bah. Pedants. :)
greyfade
Sometimes there's a historical record for why a decision was made in the standard, but don't knock somebody for telling it the way it is.
Mark Ransom
The history is nice, but the question is "why the following code is giving me the following error" and "because the standard says so" is a valid answer to that question.
Max Lybbert
minor nitpick:it's not promoted,but converted to either char or float. the difference is important. promotion is preferred to conversion.from into to something else, you can only convert. but if you had passed a short,then if you have a int and a char as overloads, the int is preferred (promotion).
Johannes Schaub - litb
gist is that promotion widens (like in char -> int), but conversion (conversion is general. when explicitly saying "integral conversion", it excludes promotions) does not like in int->float. Rules are sometimes more precise: bool->long is integral conversion, but bool->int is integral promotion.
Johannes Schaub - litb
i've some stuff about that here: http://stackoverflow.com/questions/550548/odd-behavior-with-operator-overloading/550564#550564 . not sure whether it helps anyone in their daily programming life. but just in case
Johannes Schaub - litb
A: 

I don't think that:

C p(0);

is being converted to:

C(float t)

you probably need to do:

C p(0.0f);
Edison Gustavo Muenz
No, that's not the problem. An implicit conversion from `0` to float *does* exist.
Konrad Rudolph