I was trying out default argument values and function overloading in c++ by compiling the following code and I was surprised by the output which was :
Line 19: error: call of overloaded 'add()' is ambiguous
The code I compiled is :
#include <iostream>
using namespace std;
void add(int a=1, int b=1){
cout<<a+b;
}
void add(){
int a =2, b=2;
cout<<a+b;
}
int main(){
add();
return 0;
}
Any explanations why it is ambiguous? Thx in advance.
Overload resolution is defined by § 13.3 of the C++ standard(s) (at least C++03 and C++11). There are three parts:
Candidate Functions
Since
add
names a function (rather than an object), § 13.3.1.1.1 defines how to determine candidate functions. Sinceadd
isn't qualified (contains no.
or->
operator), clause 3 applies (taken from draft n3337 of C++11):In short, the candidate functions are those found by standard name lookup in the context of the function call. Name lookup is defined in § 3.4. Often, § 3.4.2 (argument-dependent name lookup) will find additional candidate functions, but there are no arguments in the function call in question, so only § 3.4.1 matters. In particular, clause 6:
In short, the current namespace and any parent namespaces are searched, and only functions already declared are considered. In the sample code, any functions declared before
main
in the global namespace with a name ofadd
are candidates:add(int, int)
andadd()
. If you were to declare (e.g.) a functionadd(float, float)
aftermain
, it wouldn't be a candidate function.Viable Functions
§ 13.3.2:
The argument list has 0 arguments.
add()
has 0 arguments, so it's viable.add(int, int)
has 2 arguments, but the first has a default argument, so it's viable. Since there are no arguments in the call, the conversion in clause 3 doesn't come into play, but it's important to be aware of the clause, especially as it points out that a function declared asint foo(int&)
can't be bound to a function callfoo(0)
, since a non-const reference (e.g.int&
) can't be bound to an rvalue (e.g. a literal 0). However,int foo(const int&)
can be bound tofoo(0)
.Best Function
§ 13.3.3 defines how one function is considered "better" than another when it comes to name resolution in terms of a partial ordering of functions:
As there are no arguments, criteria 1 can't be used. Neither
add()
noradd(int,int)
is a template, so neither 2 nor 3 can be used. In short, neither function is better than the other.Lastly, § 13.3.3 2 determines the final result:
Since there are two viable functions in the sample code, the call is ill-formed.
You should not give
a
andb
default values. With default values there is no way for the compiler to know whether a call toadd()
should use the first or second function.Is there a reason you need to give
a
andb
default values?Because both signatures match the call.
can be interpreted as either
add(1,1)
oradd()
. When you writevoid add(int a=1, int b=1)
, you're telling the compiler - "Listen dude, if I calladd
with no parameters, I want you to default them to1
"Most importantly, what do YOU expect to happen when you call
add()
with no parameters?If you expect it to print
2
, remove the version that takes no parameters.If you expect it to print
4
, remove the default parameters from the first version.