2

I tried to overload these functions and got error saying the function call is ambiguous.

#include <iostream>
using namespace std;
double volume(int a){
    return a*a*a;
}
double volume(int a, int b, int c){
    return b*c*a;

}
double volume(int a, int b){
    return a*a*b;
}
double volume(double a, double b, double c){
    return a*b*c*2.5;
}
int main(){
    cout<<volume(2)<<endl;
    cout<<volume(2,3)<<endl;
    cout<<volume(2,2,3)<<endl;
    cout<<volume(2.0,9.7,3)<<endl;//error here
    return 0;
}

The error I got was like this

error: call of overloaded ‘volume(double, double, int)’ is ambiguous

Sailesh Dahal
  • 159
  • 1
  • 9
  • What should the compiler think about 3? – zdf Jul 21 '18 at 04:34
  • How is the compiler supposed to know whether you want to implicitly convert 3 (an int since there isn't a decimal point) to a double or convert 2.0 and 9.7 to ints? – eesiraed Jul 21 '18 at 04:52

4 Answers4

3

The compiler was confused when you called volume(double, double, int) as should compiler convert doubles to ints and call volume(int, int, int) or should it convert int to double and call volume(double, double, double).


For Advanced Readers

How does overloading works?

There are 3 steps to overload resolution.

  1. Finding the Candidate Functions : The functions with same name as called function are called candidate functions. In your case, all functions named volume are candidate Functions, because you called volume(..)

  2. Finding the Viable Functions : A function must meet two tests to be viable First, The function must have same number of parameters as there are arguments in the call. (except default arguments). Second, Each argument must match--or be convertible to the types of it's corresponding parameters. In your case, volume(int,int,int) and volume(double, double, double) are viable functions.

  3. Finding the best match if any : Last step of overload resolution determines the viable function(s) that has best match for the arguments. The best here means -- a exact type match is better than a match that requires a conversion from argument to parameters type. In your case there is no best match. Your call volume(double, double, int) doesn't matches with any viable function.


Problem with multiple parameters

Let's look at this example of rather a simpler case

void foo(int x, int y);
void foo(double x, double y);

Suppose we make a call as

foo(4.2, 5) //double and int

The above two foo, are candidate Functions (same name).

And they both are viable function as well because call can be made by conversion and both take 2 arguments.

So now compiler decides argument by argument which function is best match.

There is a match if there is only and only one function for which :

1. The match for each argument is no worse than match required by any other viable function

2. There is at least one argument for which the match is better than the match provided by any other viable function

So, when compiler checks first argument by first parameter of viable function, it chooses that foo(double, double) is the best match, but when it checks the second argument it finds that foo(int, int) is a better match.

The call is therefore ambiguous. Each viable function is better match on one of the argument to the call.


Solution

To resolve such ambiguity, you need to make sure that compiler is able to find best matches. So you need to convert the arguments explicitly. In your case you can either convert doubles to ints or last int to double. This call will not be ambiguous :

volume(2.0, 9.7, static_cast<double>(3));

Why static_cast?? Well in general you can directly write 3.0 instead and it will work fine but you cannot do it with some variables let's say

int x = 10;
float a= 2.1, b=4.8;
for(int t=1;t<=x;t++){
   volume(a,b,static_cast<double>(t));
   //do something with t here 
}

NOTE

You shouldn't try to explicitly convert arguments in function call for overloading in general. Rather you should make a new overloaded function with what you are trying to do. But I hope you are doing this just for learning, it's all fine. In projects you must avoid these explicit conversions.

Community
  • 1
  • 1
coder3101
  • 3,920
  • 3
  • 24
  • 28
2

GCC scanner is tokenizing 3 as an int instead of double

Change volume(2.0,9.7,3) to volume(2.0,9.7,3.0)

Depend on these two function:

double volume(double a, double b, double c)
double volume(int a, int b, int c)

You can have volume(2.0,9.7,3.0) or volume(2,9,3)

Comment bellow if there was any problem

Vala Khosravi
  • 2,352
  • 3
  • 22
  • 49
  • why is it not working when i change all double type to float and call function as volume(2.0,9.7,3.0) – Sailesh Dahal Jul 21 '18 at 05:34
  • Check [this](https://stackoverflow.com/questions/2386772/what-is-the-difference-between-float-and-double/2386882) out @SaileshDahal – Vala Khosravi Jul 21 '18 at 05:37
  • 1
    @Sailesh - because the choices the compile has are convert all three arguments from `double` to `float`, or to convert all three arguments from `double` to `int` in order to pick which function to call. And both options are again equally viable. – Peter Jul 21 '18 at 06:08
1

In volume(2.0,9.7,3), both 2.0 and 9.7 are literal values of type double, but 3 is of type int.

The compiler therefore has two equally viable options, among the versions of volume() you have provided;

  • Convert the two double values to int, and call the version of volume() that accepts three int arguments.

  • Convert the int value to double, and call the version of volume() that accepts three double arguments.

Both options are equally viable - under rules of the language, there is no reason to prefer one over the other, since there are conversions in both cases. Hence the error message.

To make things unambiguous for the compiler, you need to remove the ambiguity by ensuring the three arguments all have the same type - since the choice is between two functions, which both have three arguments of the same type (double or int). One way is to provide three int values (e.g. volume(2,9,3)) or three double values (e.g. volume(2.0, 9.7, 3.0)).

Peter
  • 35,646
  • 4
  • 32
  • 74
0

the compiler try to do some implicit conversion (double to int) you have here 2 matches

double volume(int a, int b, int c)
double volume(double a, double b, double c)

change cout<<volume(2.0,9.7,3)<<endl to cout<<volume(2.0,9.7,3.0)<<endl

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
moshe
  • 29
  • 1
  • Always try to include proper code blocks with an example for the OP or anyone else coming here to understand clearly. Congrats on your first answer :) – Amruth Pillai Jul 21 '18 at 05:13