Where to put default parameter value in C++?
Solution 1
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.
Solution 2
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.
Solution 3
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!).
Solution 4
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!
Solution 5
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.
Comments
-
Thomson almost 4 years
What's the place for the default parameter value? Just in function definition, or declaration, or both places?
-
Alex S over 13 yearsThat may be technically correct, but I wouldn't consider it good advice.
-
Matthieu M. over 13 years+1: even though you're technically allowed to choose, doing it in the declaration is the only self-documenting way.
-
Bo Persson over 13 yearsIf you want to be REALLY horrible, you can actually do both, but for different parameters. :-)
-
sharptooth over 13 years@Bo Persson: Great idea. Except we already have templates for being as horrible as one wants.
-
Janik Zikovsky about 11 years@sharptooth: and macros :)
-
Mooing Duck over 10 yearsI don't have a problem with these comments, since 99.99% of the time the parameter is simply value-initialized.
-
Lightness Races in Orbit about 10 yearsRelevant 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 [..] -
Patrizio Bertoni about 9 yearsdoing either for me produces the following g++
error: default argument given for parameter <x> of <fun(args)> [-fpermissive] ..... after previous specification in <fun(args)> [-fpermissive]
-
Lysol over 8 yearsI 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.
-
Alex S over 8 years@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.
-
dwanderson over 8 yearsThought 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?)
-
Paulo Carvalho almost 8 yearsNeither 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.
-
Beyondo over 5 yearsCannot we assign the parameter to an object by default? like
void test(obj, a, b = a);
-
CoffeeTableEspresso over 3 yearsThis 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).
-
Gufino2 almost 3 yearsThat'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.