What's the place for the default parameter value? Just in function definition, or declaration, or both places?
10 Answers
Default parameter values must appear on the declaration, since that is the only thing that the caller sees.
EDIT: As others point out, you can have the argument on the definition, but I would advise writing all code as if that wasn't true.

- 181,030
- 38
- 327
- 365
-
51+1: even though you're technically allowed to choose, doing it in the declaration is the only self-documenting way. – Matthieu M. Feb 14 '11 at 07:56
-
I wonder if there are any cases where it would make sense for the defaults be implementation-specific. Which makes me wonder something else: Is it possible to mix it up? Like have one parameter have a default set in the implementation, and one in the declaration? Not sure why you'd want to do that. But still curious. – Lysol Dec 11 '15 at 03:20
-
1@AidanMueller That's not possible. The default is passed by the caller based on the declaration it saw, not the value specified in the definition. – Marcelo Cantos Dec 11 '15 at 03:23
You can do either, but never both. Usually you do it at function declaration and then all callers can use that default value. However you can do that at function definition instead and then only those who see the definition will be able to use the default value.

- 1
- 1

- 167,383
- 100
- 513
- 979
-
27That may be technically correct, but I wouldn't consider it good advice. – Marcelo Cantos Feb 14 '11 at 06:43
-
35If you want to be REALLY horrible, you can actually do both, but for different parameters. :-) – Bo Persson Feb 14 '11 at 21:03
-
10@Bo Persson: Great idea. Except we already have templates for being as horrible as one wants. – sharptooth Feb 15 '11 at 05:32
-
8
-
doing either for me produces the following g++ `error: default argument given for parameter
of – Patrizio Bertoni Apr 19 '15 at 08:15[-fpermissive] ..... after previous specification in [-fpermissive]` -
Thought I needed it on both, so this was helpful, at least to say *that* you can't do both (though a little more on the *why* might be nice?) – dwanderson Dec 18 '15 at 16:30
-
Neither way works for me (MinGW). If I do it in the header I get "no matching function..." errors. If I do it in the cpp, I get linker errors... How I miss Java... I ended up writing an overloaded function. – Paulo Carvalho Aug 13 '16 at 21:12
C++ places the default parameter logic in the calling side, this means that if the default value expression cannot be computed from the calling place, then the default value cannot be used.
Other compilation units normally just include the declaration so default value expressions placed in the definition can be used only in the defining compilation unit itself (and after the definition, i.e. after the compiler sees the default value expressions).
The most useful place is in the declaration (.h) so that all users will see it.
Some people like to add the default value expressions in the implementation too (as a comment):
void foo(int x = 42,
int y = 21);
void foo(int x /* = 42 */,
int y /* = 21 */)
{
...
}
However, this means duplication and will add the possibility of having the comment out of sync with the code (what's worse than uncommented code? code with misleading comments!).

- 112,025
- 15
- 165
- 265
-
I don't have a problem with these comments, since 99.99% of the time the parameter is simply value-initialized. – Mooing Duck Oct 18 '13 at 21:24
Although this is an "old" thread, I still would like to add the following to it:
I've experienced the next case:
- In the header file of a class, I had
int SetI2cSlaveAddress( UCHAR addr, bool force );
- In the source file of that class, I had
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force = false ) { ... }
As one can see, I had put the default value of the parameter "force" in the class source file, not in the class header file.
Then I used that function in a derived class as follows (derived class inherited the base class in a public way):
SetI2cSlaveAddress( addr );
assuming it would take the "force" parameter as "false" 'for granted'.
However, the compiler (put in c++11 mode) complained and gave me the following compiler error:
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp: In member function 'void CMax6956Io::Init(unsigned char, unsigned char, unsigned int)':
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: error: no matching function for call to 'CMax6956Io::SetI2cSlaveAddress(unsigned char&)'
/home/.../mystuff/domoproject/lib/i2cdevs/max6956io.cpp:26:30: note: candidate is:
In file included from /home/geertvc/mystuff/domoproject/lib/i2cdevs/../../include/i2cdevs/max6956io.h:35:0,
from /home/geertvc/mystuff/domoproject/lib/i2cdevs/max6956io.cpp:1:
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: int CI2cHal::SetI2cSlaveAddress(unsigned char, bool)
/home/.../mystuff/domoproject/lib/i2cdevs/../../include/i2chal/i2chal.h:65:9: note: candidate expects 2 arguments, 1 provided
make[2]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/max6956io.cpp.o] Error 1
make[1]: *** [lib/i2cdevs/CMakeFiles/i2cdevs.dir/all] Error 2
make: *** [all] Error 2
But when I added the default parameter in the header file of the base class:
int SetI2cSlaveAddress( UCHAR addr, bool force = false );
and removed it from the source file of the base class:
int CI2cHal::SetI2cSlaveAddress( UCHAR addr, bool force )
then the compiler was happy and all code worked as expected (I could give one or two parameters to the function SetI2cSlaveAddress()
)!
So, not only for the user of a class it's important to put the default value of a parameter in the header file, also compiling and functional wise it apparently seems to be a must!

- 1,914
- 17
- 22
-
1This is because the caller needs to know what parameters the function takes, so the declaration that the caller sees (normally in the header file) needs to have this information (including things like default values). – CoffeeTableEspresso Dec 10 '20 at 20:31
-
6502's answer (https://stackoverflow.com/a/4989591/1047213) explains why this happens. – Hari Feb 27 '23 at 14:17
One more point I haven't found anyone mentioned:
If you have virtual method, each declaration can have its own default value!
It depends on the interface you are calling which value will be used.
Example on ideone
struct iface
{
virtual void test(int a = 0) { std::cout << a; }
};
struct impl : public iface
{
virtual void test(int a = 5) override { std::cout << a; }
};
int main()
{
impl d;
d.test();
iface* a = &d;
a->test();
}
It prints 50
I strongly discourage you to use it like this
This is because it is impl
's test
function that executes in both cases even though the default argument value is picked from impl
in d.test()
and from iface
in a->test()
. Refer Gufino2's comment below, also. He is referring to Item 37 of Effective C++.
-
1Cannot we assign the parameter to an object by default? like `void test(obj, a, b = a);` – Beyondo Mar 06 '19 at 20:49
-
1That's because, even in virtual functions, the default value of the parameter is STATICALLY bound: that means that the default value of the parameter is chosen evaluating the static type of the variable. In this case, even if a points to a impl object, a is a ptr to iface, and when you call a->test() the compiler uses the default parameter from iface. That's why it's an HORRIBLE idea to change default param values in overrides. Scott Meyers talks about that in one of his books. – Gufino2 Jul 27 '21 at 11:31
If the functions are exposed - non-member, public or protected - then the caller should know about them, and the default values must be in the header.
If the functions are private and out-of-line, then it does make sense to put the defaults in the implementation file because that allows changes that don't trigger client recompilation (a sometimes serious issue for low-level libraries shared in enterprise scale development). That said, it is definitely potentially confusing, and there is documentation value in presenting the API in a more intuitive way in the header, so pick your compromise - though consistency's the main thing when there's no compelling reason either way.

- 102,968
- 15
- 177
- 252
the declaration is generally the most 'useful', but that depends on how you want to use the class.
both is not valid.

- 104,054
- 14
- 179
- 226
Good question... I find that coders typically use the declaration to declare defaults. I've been held to one way (or warned) or the other too based on the compiler
void testFunct(int nVal1, int nVal2=500);
void testFunct(int nVal1, int nVal2)
{
using namespace std;
cout << nVal1 << << nVal2 << endl;
}

- 1,180
- 7
- 9
You may do in either (according to standard), but remember, if your code is seeing the declaration without default argument(s) before the definition that contains default argument, then compilation error can come.
For example, if you include header containing function declaration without default argument list, thus compiler will look for that prototype as it is unaware of your default argument values and hence prototype won't match.
If you are putting function with default argument in definition, then include that file but I won't suggest that.

- 1,246
- 10
- 20
Adding one more point. Function declarations with default argument should be ordered from right to left and from top to bottom.
For example in the below function declaration if you change the declaration order then the compiler gives you a missing default parameter error. Reason the compiler allows you to separate the function declaration with default argument within the same scope but it should be in order from RIGHT to LEFT (default arguments) and from TOP to BOTTOM(order of function declaration default argument).
//declaration
void function(char const *msg, bool three, bool two, bool one = false);
void function(char const *msg, bool three = true, bool two, bool one); // Error
void function(char const *msg, bool three, bool two = true, bool one); // OK
//void function(char const *msg, bool three = true, bool two, bool one); // OK
int main() {
function("Using only one Default Argument", false, true);
function("Using Two Default Arguments", false);
function("Using Three Default Arguments");
return 0;
}
//definition
void function(char const *msg, bool three, bool two, bool one ) {
std::cout<<msg<<" "<<three<<" "<<two<<" "<<one<<std::endl;
}

- 8,204
- 6
- 48
- 78

- 8,481
- 2
- 52
- 43
-
2Relevant language: `[C++11: 8.3.6/4]:` _[..]_ In a given function declaration, each parameter subsequent to a parameter with a default argument shall have a default argument supplied in this or a previous declaration _[..]_ – Lightness Races in Orbit Jun 18 '14 at 14:19
-
More examples here: https://www.ibm.com/docs/en/zos/2.1.0?topic=only-restrictions-default-arguments-c – Hari Feb 27 '23 at 14:18