Default Parameters
In-Depth Rules
Default parameters must be specified from right to left in the parameter list. Once a parameter is given a default value, all parameters to its right must also have defaults.
Provide a parameter’s default at most once in a given scope—usually in a header declaration. Do not repeat the same default in both a declaration and a definition.
Default arguments are looked up and bound at the call site. The default must therefore be visible to the caller. If you change a default in a header, callers must be recompiled to pick it up.
Advanced Usage
A default argument can be almost any expression that is valid at the call site, including function calls. It does NOT have to be a compile-time constant. The expression is evaluated each time the call uses the default.
Later parameters’ defaults can refer to earlier parameters in the same parameter list, but not vice versa.
#include <iostream>
using namespace std;
int nextId() { static int id = 0; return ++id; }
void setup(
const string& name,
int threshold = 50,
int maxItems = nextId(), // function call OK; evaluated when default is used
bool logging = false
) {
cout << name << ": th=" << threshold << ", max=" << maxItems << ", log=" << boolalpha << logging << '\n';
}
int main() {
setup("alpha"); // nextId() called here
setup("beta", 10); // nextId() called again
}
Templated Defaults
Templates can also provide defaults—for template parameters and for function parameters inside templates—reducing verbosity for common cases.
// Class template with a default template argument
template <typename T = int>
class Container {
T value{}; // defaults to int if T not specified
public:
explicit Container(T v = {}) : value(v) {}
const T& get() const { return value; }
};
Container<> c1; // uses T=int
Container<double> c2{3.14}; // explicit T
// Function template with a defaulted function parameter
template <typename T = long>
T add(T a, T b = T{1}) { return a + b; }
int x = add(4); // T deduced as long -> 4 + 1L
int y = add<int>(4); // T forced to int -> 4 + 1
Design Considerations
Default parameters can improve convenience but may also reduce clarity. Consider:
- Using overloads when different parameter combinations change behavior significantly.
- Documenting defaults clearly where the function is declared (headers).
- Avoiding defaults with surprising side effects (e.g., calling a function with observable state changes).
- Being careful when mixing overloads and defaults—certain combinations can create ambiguous calls.