Advertisement
Advertisement


Returning multiple values from a C++ function


Question

Is there a preferred way to return multiple values from a C++ function? For example, imagine a function that divides two integers and returns both the quotient and the remainder. One way I commonly see is to use reference parameters:

void divide(int dividend, int divisor, int& quotient, int& remainder);

A variation is to return one value and pass the other through a reference parameter:

int divide(int dividend, int divisor, int& remainder);

Another way would be to declare a struct to contain all of the results and return that:

struct divide_result {
    int quotient;
    int remainder;
};

divide_result divide(int dividend, int divisor);

Is one of these ways generally preferred, or are there other suggestions?

Edit: In the real-world code, there may be more than two results. They may also be of different types.

2008/11/26
1
250
11/26/2008 3:38:02 PM

Accepted Answer

For returning two values I use a std::pair (usually typedef'd). You should look at boost::tuple (in C++11 and newer, there's std::tuple) for more than two return results.

With introduction of structured binding in C++ 17, returning std::tuple should probably become accepted standard.

2018/03/26
221
3/26/2018 7:06:34 PM


Personally, I generally dislike return parameters for a number of reasons:

  • it is not always obvious in the invocation which parameters are ins and which are outs
  • you generally have to create a local variable to catch the result, while return values can be used inline (which may or may not be a good idea, but at least you have the option)
  • it seems cleaner to me to have an "in door" and an "out door" to a function -- all the inputs go in here, all the outputs come out there
  • I like to keep my argument lists as short as possible

I also have some reservations about the pair/tuple technique. Mainly, there is often no natural order to the return values. How is the reader of the code to know whether result.first is the quotient or the remainder? And the implementer could change the order, which would break existing code. This is especially insidious if the values are the same type so that no compiler error or warning would be generated. Actually, these arguments apply to return parameters as well.

Here's another code example, this one a bit less trivial:

pair<double,double> calculateResultingVelocity(double windSpeed, double windAzimuth,
                                               double planeAirspeed, double planeCourse);

pair<double,double> result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.first << endl;
cout << result.second << endl;

Does this print groundspeed and course, or course and groundspeed? It's not obvious.

Compare to this:

struct Velocity {
    double speed;
    double azimuth;
};
Velocity calculateResultingVelocity(double windSpeed, double windAzimuth,
                                    double planeAirspeed, double planeCourse);

Velocity result = calculateResultingVelocity(25, 320, 280, 90);
cout << result.speed << endl;
cout << result.azimuth << endl;

I think this is clearer.

So I think my first choice in general is the struct technique. The pair/tuple idea is likely a great solution in certain cases. I'd like to avoid the return parameters when possible.

2008/11/26

std::pair<int, int> divide(int dividend, int divisor)
{
   // :
   return std::make_pair(quotient, remainder);
}

std::pair<int, int> answer = divide(5,2);
 // answer.first == quotient
 // answer.second == remainder

std::pair is essentially your struct solution, but already defined for you, and ready to adapt to any two data types.

2008/11/26

It's entirely dependent upon the actual function and the meaning of the multiple values, and their sizes:

  • If they're related as in your fraction example, then I'd go with a struct or class instance.
  • If they're not really related and can't be grouped into a class/struct then perhaps you should refactor your method into two.
  • Depending upon the in-memory size of the values you're returning, you may want to return a pointer to a class instance or struct, or use reference parameters.
2008/11/26

The OO solution for this is to create a ratio class. It wouldn't take any extra code (would save some), would be significantly cleaner/clearer, and would give you some extra refactorings letting you clean up code outside this class as well.

Actually I think someone recommended returning a structure, which is close enough but hides the intent that this needs to be a fully thought-out class with constructor and a few methods, in fact, the "method" that you originally mentioned (as returning the pair) should most likely be a member of this class returning an instance of itself.

I know your example was just an "Example", but the fact is that unless your function is doing way more than any function should be doing, if you want it to return multiple values you are almost certainly missing an object.

Don't be afraid to create these tiny classes to do little pieces of work--that's the magic of OO--you end up breaking it down until every method is very small and simple and every class small and understandable.

Another thing that should have been an indicator that something was wrong: in OO you have essentially no data--OO isn't about passing around data, a class needs to manage and manipulate it's own data internally, any data passing (including accessors) is a sign that you may need to rethink something..

2008/11/26

With C++17 you can also return one ore more unmovable/uncopyable values (in certain cases). The possibility to return unmovable types come via the new guaranteed return value optimization, and it composes nicely with aggregates, and what can be called templated constructors.

template<typename T1,typename T2,typename T3>
struct many {
  T1 a;
  T2 b;
  T3 c;
};

// guide:
template<class T1, class T2, class T3>
many(T1, T2, T3) -> many<T1, T2, T3>;

auto f(){ return many{string(),5.7, unmovable()}; }; 

int main(){
   // in place construct x,y,z with a string, 5.7 and unmovable.
   auto [x,y,z] = f();
}

The pretty thing about this is that it is guaranteed to not cause any copying or moving. You can make the example many struct variadic too. More details:

Returning variadic aggregates (struct) and syntax for C++17 variadic template 'construction deduction guide'

2017/05/23

Source: https://stackoverflow.com/questions/321068
Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Email: [email protected]