Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overload resolution with multiple functions and multiple conversion operators

Consider simple code :

#include<iostream>

struct A {
    operator double(){
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    }
    operator char(){
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    }
} a;

void foo(int){}
void foo (char){}
int main() {
    foo(a);
}

Above code works fine, and as expected gcc, clang and VC++ chooses foo(char).

Now lets modify the code little bit :

#include<iostream>

struct A {
    operator double(){
        std::cout<<"Conversion function double chosen."<<std::endl;
        return 1.1;
    }
    operator char(){
        std::cout<<"Conversion function char chosen."<<std::endl;
        return 'a';
    }
} a;

void foo(int){}
void foo (double){} //parameter changed from char to double
int main() {
    foo(a);
}

Now this should have choose foo(double), but seems only VC++ is happy with the code while clang and gcc are unhappy with the above code.

main.cpp:11:10: error: call of overloaded 'foo(A&)' is ambiguous
 foo(a);
     ^
main.cpp:8:6: note: candidate: void foo(int)
 void foo(int){}
      ^
main.cpp:9:6: note: candidate: void foo(double)
 void foo (double){} //parameter changed from char to double
      ^

Can anyone explain why above code fails? or is it bug?.

One more question: Do gcc and clang share code of overload resolution?

like image 628
Angelus Mortis Avatar asked Mar 17 '16 19:03

Angelus Mortis


People also ask

What is overload resolution?

The process of selecting the most appropriate overloaded function or operator is called overload resolution. Suppose that f is an overloaded function name. When you call the overloaded function f() , the compiler creates a set of candidate functions.

What is function overloading How are function calls matched with overloaded functions explain with the help of an example?

Function Overloading in C++When a function name is overloaded with different jobs it is called Function Overloading. In Function Overloading “Function” name should be the same and the arguments should be different. Function overloading can be considered as an example of a polymorphism feature in C++.

Can functions with different return types be overloaded?

The return type of a function has no effect on function overloading, therefore the same function signature with different return type will not be overloaded. Example: if there are two functions: int sum() and float sum(), these two will generate a compile-time error as function overloading is not possible here.

How do you fix an ambiguous call to overloaded function?

There are two ways to resolve this ambiguity: Typecast char to float. Remove either one of the ambiguity generating functions float or double and add overloaded function with an int type parameter.


2 Answers

A -> char is A -> char.

A -> int is A -> char -> int (because char to int is a promotion and so beats the double to int conversion).

A -> double is A -> double.

Two user-defined conversion sequences are only comparable if they involve the same user-defined conversion function. Thus, A -> char is a better conversion sequence than A -> int, so your first case is unambiguous. Neither A -> int nor A -> double is better than the other, so the second case is ambiguous.

like image 166
T.C. Avatar answered Nov 02 '22 10:11

T.C.


TL;DR: The difference is that in the first case, as opposed to the second, the user-defined conversion sequences (A -> char, A -> int) call the same conversion function (operator char). That enables us to break the tie via [over.ics.rank]/(3.3).


The best conversion operators for particular functions are selected by [over.match.best]/(1.4) (comparing the conversion sequences of their return types).

Hence the better conversion function for foo(int) is operator char followed by a promotion to int, as opposed to operator double followed by a floating point conversion.

Now consider both variants of the second overload:

  1. The best ICS to foo(char) is also via operator char (identity better than floating point conversion). Thus [over.ics.rank]/(3.3) is applicable:

    User-defined conversion sequence U1 is a better conversion sequence than another user-defined conversion sequence U2 if they contain the same user-defined conversion function […] and in either case the second standard conversion sequence of U1 is better than the second standard conversion sequence of U2.

    Hence the overall conversion to F2 is deemed better, and it is selected.

  2. The best ICS to foo(double) is via operator double. We end up with two conversion sequences employing distinct conversion functions; nothing really applies, and we just get an ambiguity.

like image 41
Columbo Avatar answered Nov 02 '22 11:11

Columbo