150

1.

int Add (int a, int b = 3);
int Add (int a, int b)
{

}

2.

int Add (int a, int b);
int Add (int a, int b = 3)
{

}

Both work; which is the standard way and why?

River
  • 8,585
  • 14
  • 54
  • 67
httpinterpret
  • 6,409
  • 9
  • 33
  • 37

5 Answers5

222

If you put the declaration in a header file, and the definition in a separate .cpp file, and #include the header from a different .cpp file, you will be able to see the difference.

Specifically, suppose:

lib.h

int Add(int a, int b);

lib.cpp

int Add(int a, int b = 3) {
   ...
}

test.cpp

#include "lib.h"

int main() {
    Add(4);
}

The compilation of test.cpp will not see the default parameter declaration, and will fail with an error.

For this reason, the default parameter definition is usually specified in the function declaration:

lib.h

int Add(int a, int b = 3);
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Then `b` will be defined multiple times,once for each compilation unit that includes `lib.h`,is that right? – httpinterpret May 16 '10 at 07:44
  • @httpinterpret: in one sense yes, the default value of `b` is defined once for *each* `.cpp` file that includes the header. But that's okay, because you've only got one declaration of the `Add` function. – Greg Hewgill May 16 '10 at 07:58
  • 1
    @httpinterpret The compiler will add the not specified parameter by the default parameter when the caller code is generted. That's why the default value MUST be in the function prototype and not in the function implementation. The parameter is not _defined_ in the sense of variable definition since the prototype does not define variables. – harper Sep 11 '13 at 15:54
  • 1
    This answer could be edited because a quick parsing (just looking at the code and not going until "For this reason,") made me understand the opposite of what you meant. – Gabriel Devillers Oct 04 '18 at 19:25
45

In C++ the requirements imposed on default arguments with regard to their location in parameter list are as follows:

  1. Default argument for a given parameter has to be specified no more than once. Specifying it more than once (even with the same default value) is illegal.

  2. Parameters with default arguments have to form a contiguous group at the end of the parameter list.

Now, keeping that in mind, in C++ you are allowed to "grow" the set of parameters that have default arguments from one declaration of the function to the next, as long as the above requirements are continuously satisfied.

For example, you can declare a function with no default arguments

void foo(int a, int b);

In order to call that function after such declaration you'll have to specify both arguments explicitly.

Later (further down) in the same translation unit, you can re-declare it again, but this time with one default argument

void foo(int a, int b = 5);

and from this point on you can call it with just one explicit argument.

Further down you can re-declare it yet again adding one more default argument

void foo(int a = 1, int b);

and from this point on you can call it with no explicit arguments.

The full example might look as follows

void foo(int a, int b);

int main()
{
  foo(2, 3);

  void foo(int a, int b = 5); // redeclare
  foo(8); // OK, calls `foo(8, 5)`

  void foo(int a = 1, int b); // redeclare again
  foo(); // OK, calls `foo(1, 5)`
}

void foo(int a, int b)
{
  // ...
}

As for the code in your question, both variants are perfectly valid, but they mean different things. The first variant declares a default argument for the second parameter right away. The second variant initially declares your function with no default arguments and then adds one for the second parameter.

The net effect of both of your declarations (i.e. the way it is seen by the code that follows the second declaration) is exactly the same: the function has default argument for its second parameter. However, if you manage to squeeze some code between the first and the second declarations, these two variants will behave differently. In the second variant the function has no default arguments between the declarations, so you'll have to specify both arguments explicitly.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I don't think your code defined void foo(int a = 1, int b) would work. You need to have all optional parameters after one optional parameter. It's a syntax error (at least with g++ 4.5.3 on my system). – Nilesh Sep 09 '11 at 13:38
  • @Nilesh: As I explicitly said above (and which is the whole point of this example) for `void foo(int a = 1, int b)` to work it has to be declared *after* `void foo(int a, int b = 5)`. Yes, it will work. And no, it is not a syntax error. g++ 4.5.3 will compile it perfectly fine. – AnT stands with Russia Sep 09 '11 at 14:11
  • Okay so the function takes value of b from the previous declaration. Getting the thing now. Thanks :-) – Nilesh Sep 09 '11 at 14:23
  • 1
    @Nilesh: Yes, the default argument declarations are accumulated across all previous declarations in the translation unit. – AnT stands with Russia Sep 09 '11 at 14:35
  • 1
    I like to write my function prototypes without variable names, like `int foo(int)`. I find that I can write `int foo(int=5)` again, leaving out the parameter names. No one seems to have mentioned that as yet. – Victor Eijkhout Feb 14 '17 at 20:46
  • @Victor Eijkhout: It is true, but not immediately relevant to the issue at hand. – AnT stands with Russia Feb 14 '17 at 20:52
5

The first way would be preferred to the second.

This is because the header file will show that the parameter is optional and what its default value will be. Additionally, this will ensure that the default value will be the same, no matter the implementation of the corresponding .cpp file.

In the second way, there is no guarantee of a default value for the second parameter. The default value could change, depending on how the corresponding .cpp file is implemented.

user342264
  • 51
  • 1
4

Default arguments must be specified with the first occurrence of the function name—typically, in the function prototype. If the function prototype is omitted because the function definition also serves as the prototype, then the default arguments should be specified in the function header.

clyfe
  • 23,695
  • 8
  • 85
  • 109
0

On thing to remember here is that the default param must be the last param in the function definition.

Following code will not compile:

void fun(int first, int second = 10, int third);

Following code will compile:

void fun(int first, int second, int third = 10);
Avtar Sohi
  • 295
  • 3
  • 4