Reading some questions here on SO about conversion operators and constructors got me thinking about the interaction between them, namely when there is an 'ambiguous' call. Consider the following code:
class A;
class B {
public:
B(){}
B(const A&) //conversion constructor
{
cout << "called B's conversion constructor" << endl;
}
};
class A {
public:
operator B() //conversion operator
{
cout << "called A's conversion operator" << endl;
return B();
}
};
int main()
{
B b = A(); //what should be called here? apparently, A::operator B()
return 0;
}
The above code displays "called A's conversion operator", meaning that the conversion operator is called as opposed to the constructor. If you remove/comment out the operator B()
code from A
, the compiler will happily switch over to using the constructor instead (with no other changes to the code).
My questions are:
- Since the compiler doesn't consider
B b = A();
to be an ambiguous call, there must be some type of precedence at work here. Where exactly is this precedence established? (a reference/quote from the C++ standard would be appreciated) - From an object-oriented philosophical standpoint, is this the way the code should behave? Who knows more about how an
A
object should become aB
object,A
orB
? According to C++, the answer isA
— is there anything in object-oriented practice that suggests this should be the case? To me personally, it would make sense either way, so I'm interested to know how the choice was made.
Thanks in advance
Best Solution
You do copy initialization, and the candidate functions that are considered to do the conversions in the conversion sequence are conversion functions and converting constructors. These are in your case
Now, that are the way you declare them. Overload resolution abstracts away from that, and transforms each candidate into a list of parameters that correspond to the arguments of the call. The parameters are
The second one is because the conversion function is a member function. The
A&
is the so-called implicit object parameter that's generated when a candidate is a member function. Now, the argument has typeA
. When binding the implicit object parameter, a non-const reference can bind to an rvalue. So, another rule says that when you have two viable functions whose parameters are references, then the candidate having the fewest const qualification will win. That's why your conversion function wins. Try makingoperator B
a const member function. You will notice an ambiguity.For the record, if you make the conversion function a const member function, then GCC will chose the constructor (so GCC seems to think that
B
has more business with it?). Switch to pedantic mode (-pedantic
) to make it cause a diagnostic.Standardese,
8.5/14
And
13.3.1.4
And
13.3.3.2/3