Default Arguments
Here is a function that logs a message to the console. With each message, it also needs to log the severity level ("INFO", "WARNING", "ERROR", etc.):
void logMessage(std::string message, std::string level) { std::cout << "[" << level << "] " << message << "\n";}Now suppose 90% of the messages logged with this function are just informational, so we are passing "INFO", over and over:
logMessage("Server started", "INFO");logMessage("Connected", "INFO");logMessage("Cache cleared", "INFO");logMessage("Disk almost full", "WARNING");This kind of repetition is annoying, and it’s also wasted effort. Noise like that can be reduced using default arguments.
Giving a parameter a default value
A default value can be assigned to a parameter by using = in the function’s parameter list:
Now both function calls, on lines 9–10, work correctly. When a call omits an argument (like on line 9), the compiler detects it and inserts the default value at the call site during compilation.
There are a few rules to keep in mind when using default arguments.
Rule 1: Defaults have to trail
Once a parameter has a default argument, all parameters after it are also required to have one. So, you can’t do this:
// This will not compile:void logMessage(std::string message, std::string level = "INFO", std::string tag) { // ...}This doesn’t work because function arguments are matched to parameters from left to right. In a call like logMessage("Disk full", "urgent"), "urgent" would be passed to the second parameter, leaving the third parameter unmatched. There’s no way to call the function so that the third parameter receives a value and the second keeps its default.
One fix would be to also give a default argument to the last parameter tag:
void logMessage(std::string message, std::string level = "INFO", std::string tag = "general") { // ...}Another would be to reorder the parameters so that tag comes first:
void logMessage(std::string message, std::string tag, std::string level = "INFO") { // ...}Rule 2: Defaults can’t reference other parameters
A parameter can’t refer to another parameter:
// This will not compile:void makeGrid(int width, int height = width) { // ...}If this were allowed, width would need to be evaluated before it’s used as a default value for height. But C++ doesn’t guarantee the order in which a function’s arguments are evaluated.
If you need a default that depends on another argument, compute it inside the function body instead:
void makeGrid(int width, int height = -1) { if (height == -1) { height = width; } // ...}Rule 3: Defaults go in declarations
If you split your code into a declaration and a separate definition (something you’ll do once you start using multiple header files), the default belongs in the declaration only, not in both places:
// declarationvoid logMessage(std::string message, std::string level = "INFO");// definition, later or in a different filevoid logMessage(std::string message, std::string level) { std::cout << "[" << level << "] " << message << "\n";}Repeating the default in the definition is a compile error.
Checkpoint
What does this program print?
void printBadge(std::string name, std::string tier = "Bronze") {
std::cout << name << ": " << tier << "\n";
}
int main() {
printBadge("Aria");
printBadge("Kai", "Gold");
}What does this print?
void printBadge(std::string name, std::string tier = "Bronze", int ranking) {
std::cout << name << ": " << tier << " (#" << ranking << ")\n";
}
int main() {
printBadge("Kai", "Gold", 1);
}What does this program print?
void printBadge(std::string name, std::string tier = "Bronze");
int main() {
printBadge("Aria");
printBadge("Kai", "Gold");
}
void printBadge(std::string name, std::string tier = "Bronze") {
std::cout << name << ": " << tier << "\n";
}Given this attempted declaration, why won’t it compile?
void allocateBuffer(int blockSize, int alignment, long capacity = blockSize) {
// ...
}