-3

When default parameters are not specified, function overloading works.

But, why doesn't function overloading work when default parameters are specified?

This program takes two integers and compares them to find the larger of the two.

Then, it compares the maximum value with bigger integers obtained earlier, and the smaller value is output.

Here's the code I written

#include <iostream>
using namespace std;

int big(int a, int b);
int big(int a, int b, int max = 100);

int big(int a, int b) {
    if (a > b)
        if (a > 100)
        {
            return 100; 
        }
        else {
            return a; 
        }
    else {
        if (b > 100) {
            return 100; 
        }
        else
        {
            return b; 
        }
    }
}

int big(int a, int b, int max) {
    if (a > b) {
        if (a < max) {
            return a; 
        }
        else
        {
            return max; 
        }
    }
    else {
        if (b < max) {
            return b; 
        }
        else {
            return max; 
        }

    }
}
  
int main() {
    int x = big(3, 5); 
    int y = big(300, 60); 
    int z = big(30, 60, 50); 
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

When I debug the code I wrote, it says

E0308 Compilation Error: More than one instance of overloaded function matches the argument list

I learned that function overloading can work when the function parameters are different.

In my code, function names are the same, but function parameters are different:

(int x, int y) and (int x, int y, int max)

But it doesn't work.

In conclusion, why does function overloading not work when default parameters are specified?

IDE that I used:

Microsoft Visual Studio Community 2022 (64-bit) - Current version. 17.5.1

Here's the desire result:

  1. Variables x and y have the return value of the first function big(int x, int y)
  2. Variable z has the return value of the second function big(int x, int y, int max = 100)

This Question is related, but I don't understand how the solution is what I want.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    How to determine which function to call if only two arguments are supplied? – Vlad from Moscow Apr 02 '23 at 09:18
  • 2
    Function overloading is overrated and can be dangerous with default parameters. This example is one of several reasons why I disallow function overloading and discourage default parameters on my team. No one ever got hurt because the functions were named differently. If you need two `big` functions, then name them explicitly: `big` and `bigWithMax` or something like that. If you need a default parameter, create a separately named stub function that takes less arguments and calls the other function with the hardcoded argument values. – selbie Apr 02 '23 at 09:23
  • 1
    Why did you give the three-argument overload a default argument if not to be able to call it with just two arguments? – molbdnilo Apr 02 '23 at 09:46
  • Imagine you do `int biggest = big(1,2);`. There are two equally viable options - the `int big(int a, int a)` or `int big(int a, int b, int max = 100)`, and the standard gives no criteria to require preferring one form over the other (whichever choice the standard made, it would be "wrong" according to *some* programmers, and SO would receive questions "why not the other choice?"). Instead, the standard calls this a diagnosable error requiring the programmer to sort things out. To fix: remove the ambiguity - either eliminate the two-argument form entirely or eliminate the default value. – Peter Apr 02 '23 at 12:02

2 Answers2

1

You've effectively got these two functions named the same

int big(int a, int b) {}

int big(int a, int b, int max=100) {}

And then when you invoke big(3,5)....

Exactly which version of big did you expect to get called? The first implementation which explicitly takes two parameters or the second implementation that can take two or three parameters?

The compiler is doing you a favor by erroring out and telling you it's ambiguous.

As I called out in my comments, function overloading is overrated. Just name the functions explicitly such that there is zero ambiguity on which implementation is getting called.

Also, your entire implementation can be simplified to just a single function and two lines of code

int big(int a, int b, int max=100) {
    int result = (a > b) ? a : b;
    return (result > max) ? max : result;
}

The default parameter for max seems innocuously ok to me if you keep it as a single function with no overloads.

selbie
  • 100,020
  • 15
  • 103
  • 173
0

This part is ambiguous, since the second function declaration has a default argument:

int big(int a, int b);
int big(int a, int b, int max = 100);

So while you call, for example, big(20,30), both versions of big() could be used. So there will be 2 candidates.

It would be enough to use the second version of your function to make it work without overloading. Something like this :

#include <iostream>
using namespace std;

// declare
int big(int a, int b, int max = 100);

// define
int big(int a, int b, int max) {
    if (a > b) {
        if (a < max) {
            return a;
        }
        else
        {
            return max;
        }
    }
    else {
        if (b < max) {
            return b;
        }
        else {
            return max;
        }

    }
}

int main() {
    int x = big(3, 5);
    int y = big(300, 60);
    int z = big(30, 60, 50);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

In case you still want to define 2 functions. I would suggest you remove the default argument.

#include <iostream>
using namespace std;

int big(int a, int b);
int big(int a, int b, int max);

int big(int a, int b) {
    if (a > b)
        if (a > 100)
        {
            return 100;
        }
        else {
            return a;
        }
    else {
        if (b > 100) {
            return 100;
        }
        else
        {
            return b;
        }
    }
}

int big(int a, int b, int max) {
    if (a > b) {
        if (a < max) {
            return a;
        }
        else
        {
            return max;
        }
    }
    else {
        if (b < max) {
            return b;
        }
        else {
            return max;
        }

    }
}

int main() {
    int x = big(3, 5);
    int y = big(300, 60);
    int z = big(30, 60, 50);
    cout << x << ' ' << y << ' ' << z << endl;
    return 0;
}

Extra note: About declare and define your functions. Since you define the function int the same source file and before main(), perhaps you do not need to declare and then define. So you could skip to declare it. If you move the implementation to another source file or after main(), then declare it. More info: Link