#105 – How to elegantly return multiple values in C++

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.