C++ is very adamant with functions returning a single type. To circumvent this, out parameters can be used. However, #100 – Why you should avoid using out parameters condones their use.
Fortunately, there is a workaround.
Passing structs (by reference)
Advantages:
- Only one function parameter
- If the struct gets more members, function doesn’t get broken
Returning a struct is especially useful when the result is a natural bundle of data.
For example, a battery monitor may report voltage, current, and temperature together:
#include <iostream>
struct BatteryReading {
double voltage {};
double current {};
double temperature {};
};
BatteryReading readBattery(){
return BatteryReading {
.voltage = 12.4,
.current = 1.8,
.temperature = 31.6
};
}
void printReading(const BatteryReading& reading){
std::cout << "Voltage: " << reading.voltage << " V\n";
std::cout << "Current: " << reading.current << " A\n";
std::cout << "Temperature: " << reading.temperature << " C\n";
}
int main(){
BatteryReading reading { readBattery() };
printReading(reading);
}
// Terminal output:
Voltage: 12.4 V
Current: 1.8 A
Temperature: 31.6 C
This design is stronger than returning three separate values through output parameters.
The function signature stays clean: BatteryReading readBattery();
NOTE: You can also pass in a temporary struct as an argument if that’s your cup of tea. However, modern C++ compilers commonly use copy elision and Return Value Optimization, where the returned object is constructed directly in the caller’s storage. What a time we live in.
Returning structs
Let’s say we want to decompose a value in seconds into minutes and seconds:
#include <iostream>
struct Duration {
int minutes {};
int seconds {};
};
Duration splitDuration(int totalSeconds){
return Duration {
.minutes = totalSeconds / 60,
.seconds = totalSeconds % 60
};
}
int main(){
Duration duration { splitDuration(367) };
std::cout << duration.minutes << " minutes, "
<< duration.seconds << " seconds\n";
}
Terminal output:
6 minutes, 7 seconds
Another example: The standard library’s div function is a classic example; it divides two integers and returns both the quotient and remainder in a single struct
struct Results {
int quotient;
int remainder;
};
// Return as a struct
Results divide(int numerator, int denominator) {
return {numerator / denominator, numerator % denominator};
}
Conclusion
A C++ function has one return type. That sounds limiting when a function naturally produces multiple related values. The solution is to use structs.