Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

conversion precedence in c++

Tags:

c++

I have the following code:

Some functions:

A::A(int i_a) {cout<<"int Ctor\n";}          //conversion constructor

void h(double d) {cout<<"double param\n";}   //f1
void h(A a) {cout<<"A param\n";}             //f2

In the main function:

h(1);

The function that h(1) calls is f1.

My question is why does it choose to call that. 1 is an int and therefore requires implicit conversion to double. It could just as easily convert the int into an A using the conversion constructor defined above. Why don't I get an error? What are the precedence rules with casting?


N.b. I've posted above the code that I think will be necessary to answer the question, but below I'm posting the entire code:

 #include <iostream>
 using namespace std;
 class B;
 class A {
 public:
 explicit A(const B&) {cout<<"Ctor through B\n";}
 A() {cout<<"Default Ctor\n";}
 A(int i_a) {cout<<"int Ctor\n";}
 operator int() {cout<<"A => int\n"; return 2;}
 };
 class B {
 public:
 operator A() const {cout<<"B => A\n"; A a; return a;}
 };
 void h(double d) {cout<<"double param\n";}
 void h(A a) {cout<<"A param\n";}
 void f(const A& a)
 {
 cout<<"f function\n";
 //Without the const it will never try to convert
 }
 void main()
 {
 B b;
 cout <<"-----------------\n";
 f(b);
 cout <<"-----------------\n";
 h(1);
 }
like image 315
Meir Avatar asked Jul 07 '09 14:07

Meir


People also ask

What is the priority among (* %) (+ -) and (=) C operators?

1) What is the Priority among (*, /, %), (+, -) and (=) C Operators.? Explanation: Assignment operator in C has the least priority.

What are conversions in C?

In C programming, we can convert the value of one data type ( int, float , double , etc.) to another. This process is known as type conversion.

How many conversions are there in C?

There are two type of conversions in C.


1 Answers

When overload resolution is performed to select the best candidate out of all viable overloads - the compiler ranks all the conversion sequences for each argument for each candidate. For a function to win (be selected as the best candidate), its conversion ranks for each argument have to be better than or equal to every other function's conversion ranks for that argument AND at least one conversion rank has to be better than all the other function's conversion ranks for a certain argument.

The user defined conversion (which uses either a constructor or a cast operator) has one of the worst possible ranks (only the ellipsis has a worse rank). The integral-floating conversion has a better rank (see below for a list of the rankings).

Thus, the compiler prefers converting an int -> double (using a standard conversion) than converting an int -> A (using a user defined conversion), and therefore it selects f1.

Edit: Although "Overload resolution" works in the background and most of the time does exactly what you would expect (i.e. most programmers won't need to delve into the technicalities) - if you do want to go deeper (but be warned that some of the darker corners of overload resolution are considered to be one of the trickiest aspects for compiler writers to get exactly right in a C++ compiler) refer to the excellent C++ Templates: The Complete Guide by David Vandevoorde and Nicolai M. Josuttis which provides, in appendix B, one of the best introductions to the machinery behind overload resolution that I have read.

Here is an excerpt from B.2:

Overload resolution ranks the viable candidate functions by comparing how each argument of the call matches the corresponding parameter of the candidates. 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. ...

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).

But that's just the beginning - if you are intrigued - I urge you to read the book and then the relevant portions of the standard :)

like image 129
Faisal Vali Avatar answered Oct 01 '22 10:10

Faisal Vali