pslayer89
pslayer89

Reputation: 317

A confusion about c++ function overloading

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.

Upvotes: 1

Views: 2440

Answers (3)

outis
outis

Reputation: 77400

Overload resolution is defined by § 13.3 of the C++ standard(s) (at least C++03 and C++11). There are three parts:

  1. determine candidate functions,
  2. determine viable functions from the candidate functions,
  3. select the best viable function.

Candidate Functions

Since add names a function (rather than an object), § 13.3.1.1.1 defines how to determine candidate functions. Since add isn't qualified (contains no . or -> operator), clause 3 applies (taken from draft n3337 of C++11):

In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls (3.4). The function declarations found by that lookup constitute the set of candidate functions. Because of the rules for name lookup, the set of candidate functions consists (1) entirely of non-member functions or (2) entirely of member functions of some class T. In case (1), the argument list is the same as the expression-list in the call. [...]

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:

A name used in the definition of a function following the function’s declarator-id that is a member of namespace N (where, only for the purpose of exposition, N could represent the global scope) shall be declared before its use in the block in which it is used or in one of its enclosing blocks (6.3) or, shall be declared before its use in namespace N or, if N is a nested namespace, shall be declared before its use in one of N’s enclosing namespaces.

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 of add are candidates: add(int, int) and add(). If you were to declare (e.g.) a function add(float, float) after main, it wouldn't be a candidate function.

Viable Functions

§ 13.3.2:

2 First, to be a viable function, a candidate function shall have enough parameters to agree in number with the arguments in the list.
  • If there are m arguments in the list, all candidate functions having exactly m parameters are viable.
  • A candidate function having fewer than m parameters is viable only if it has an ellipsis in its parameter list (8.3.5). For the purposes of overload resolution, any argument for which there is no corresponding parameter is considered to "match the ellipsis" (13.3.3.1.3).
  • A candidate function having more than m parameters is viable only if the (m+1)-st parameter has a default argument (8.3.6). For the purposes of overload resolution, the parameter list is truncated on the right, so that there are exactly m parameters.
3 Second, for F to be a viable function, there shall exist for each argument an implicit conversion sequence (13.3.3.1) that converts that argument to the corresponding parameter of F. If the parameter has reference type, the implicit conversion sequence includes the operation of binding the reference, and the fact that an lvalue reference to non-const cannot be bound to an rvalue and that an rvalue reference cannot be bound to an lvalue can affect the viability of the function (see 13.3.3.1.4).

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 as int foo(int&) can't be bound to a function call foo(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 to foo(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:

  1. Some conversions are "better" than others (§13.3.3.2), and a function that uses better argument conversions is a better function.
  2. If 1 doesn't determine the better function, non-template functions are better than template functions.
  3. If 2 doesn't determine the better function, then a function template specialization that is more specialized than another is better ("more specialized" is a partial ordering of defined in § 14.5.6.2).

As there are no arguments, criteria 1 can't be used. Neither add() nor add(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:

If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution; otherwise the call is ill-formed.

Since there are two viable functions in the sample code, the call is ill-formed.

Upvotes: 2

diolemo
diolemo

Reputation: 2661

void add(int a, int b);
void add();

You should not give a and b default values. With default values there is no way for the compiler to know whether a call to add() should use the first or second function.

Is there a reason you need to give a and b default values?

Upvotes: 2

Luchian Grigore
Luchian Grigore

Reputation: 258548

Because both signatures match the call.

add();

can be interpreted as either add(1,1) or add(). When you write void add(int a=1, int b=1), you're telling the compiler - "Listen dude, if I call add with no parameters, I want you to default them to 1"

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.

Upvotes: 8

Related Questions