How can functions return several values?

Consider the problem of computing three statistics for a given list of integers: the maximum, the minimum, and the average. These statistics can be used to create a summarized view of the data. Assume the list of integers is stored in a vector. One can then have three different functions, each computing (and returning) one of these statistics.

// Return the minimum value stored in V
int min(const std::vector<int>& V);

// Return the maximum value stored in V
int max(const std::vector<int>& V);

// Return the average of the values stored in V
double average(const std::vector<int>& V);

Each of these functions loops through the values stored in the vector, like

for(int e : V){
   //Do something
}

Thus, if one uses the functions above to compute the maximum, the minimum, and the average of the values stored in a vector then one has to loop through the vector three times.

std::vector<int> list = {-1, 99, 0, -10, 2};

int minimum = min(list);    // loops through the list of values
int maximum = max(list);    // loops once more through the list of values
double avg = average(list); // and again loops through the list of values

One can, however, think of a more time efficient function: loop once through the vector, compute all three values, and return them. A sketch of the function could look something like the following (not yet compilable C++):

// Return the min, the max, and the average of the values in V
???? max_min_avg(const std::vector<int>& V) { // how can a function return several values??
    int min = V[0];
    int max = V[0];

    double sum = 0.0;

    for (int e : V) {
        if (e < min) {
            min = e;
        } else if (e > max) {
            max = e;
        }
        sum += e;
    }

    return ???? // min, max, sum / std::ssize(V) ;
}

The problem to put this idea in practice is that functions can only return one value (or nothing, void). So, how can one write a function that returns three values? A first idea could be to store the three values, the maximum, the minimum, and the average, in a vector of three slots. The problem is that all values stored in a vector must be of the same type, and in our case we have two values of type int (the the maximum and the minimum) and one value of type double (the average). So vectors are not going to help us.

One way to address this problem is to use a struct to define a new data type, let’s say called Three_number_summary, with three data members, one for each of the the three statistics.

struct Three_number_summary {
    int maximum = 0;
    int minimum = 0;
    double average = 0.0;
};

Next, we can define one single function that computes the three statistics and returns a value of type Three_number_summary. As you can see, this function loops only once through the vector.

// Compute the maximum, minimum, and average for values stored in V
// Assumption: V is not an empty vector
Three_number_summary compute_three_number_summary(const std::vector<int>& V) {
    int min = V[0];
    int max = V[0];
    double sum = 0.0;
	 
    for(int e : V){
        if (e < min) {
            min = e;
        } else if (e > max) {
            max = e;
        }
        sum += e;
    }
    return {min, max, sum / std::ssize(V)};
	
    /*
    Three_number_summary summary = {min, max, sum / std::ssize(V)};
    return summary;
    */
   }
}