Your add function is not a good example of how to use the default parameters, and you are right that with one it is more difficult to read.
However, this is not true for all functions. Consider std :: vector :: resize, which looks something like this:
template<class T> struct vector_imitation { void resize(int new_size, T new_values=T()); };
Here resizing without providing a value uses T (). This is a very common case, and I believe that almost everyone finds a one-parameter call for resizing in order to understand:
vector_imitation<int> v; // [] (v is empty) v.resize(3); // [0, 0, 0] (since int() == 0) v.resize(5, 42); // [0, 0, 0, 42, 42]
The new_value parameter is created even if it is never needed: when resizing to a smaller size. Thus, for some overload functions, it is better than the default parameters. (I would include vector :: resize in this category.) For example, std :: getline works this way, although it has no other choice, since the default value for the third parameter is calculated from the first parameter. Something like:
template<class Stream, class String, class Delim> Stream& getline_imitation(Stream &in, String &out, Delim delim); template<class Stream, class String> Stream& getline_imitation(Stream &in, String &out) { return getline_imitation(in, out, in.widen('\n')); }
Default parameters would be more useful if you could specify named parameters for functions, but C ++ does not make this easy. If you encounter default parameters in other languages, you need to keep this restriction in C ++. For example, imagine a function:
void f(int a=1, int b=2);
You can only use the default setpoint for a parameter if you also use the default setpoints for all later parameters instead of ringing, for example:
f(b=42)