Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I return hundreds of values from a C++ function?

In C++, whenever a function creates many (hundreds or thousands of) values, I used to have the caller pass an array that my function then fills with the output values:

void computeValues(int input, std::vector<int>& output);

So, the function will fill the vector output with the values it computes. But this is not really good C++ style, as I'm realizing now.

The following function signature is better because it doesn't commit to using a std::vector, but could use any container:

void computeValues(int input, std::insert_iterator<int> outputInserter);

Now, the caller can call with some inserter:

std::vector<int> values; // or could use deque, list, map, ...
computeValues(input, std::back_inserter(values));

Again, we don't commit to using std::vector specifically, which is nice, because the user might just need the values in a std::set etc. (Should I pass the iterator by value or by reference?)

My question is: Is the insert_iterator the right or standard way to do it? Or is there something even better?

EDIT: I edited the question to make it clear that I'm not talking about returning two or three values, but rather hundreds or thousands. (Imagine you have return all the files you find in a certain directory, or all the edges in a graph etc.)

like image 882
Frank Avatar asked Nov 30 '22 07:11

Frank


1 Answers

Response to Edit: Well, if you need to return hundreds and thousands if values, a tuple of course would not be the way to go. Best pick the solution with the iterator then, but it's best not use any specific iterator type.


If you use iterators, you should use them as generic as possible. In your function you have used an insert iterator like insert_iterator< vector<int> >. You lost any genericity. Do it like this:

template<typename OutputIterator>
void computeValues(int input, OutputIterator output) {
    ...
}

Whatever you give it, it will work now. But it will not work if you have different types in the return set. You can use a tuple then. Also available as std::tuple in the next C++ Standard:

boost::tuple<int, bool, char> computeValues(int input) { 
    ....
}

If the amount of values is variadic and the type of the values is from a fixed set, like (int, bool, char), you can look into a container of boost::variant. This however implies changes only on the call-side. You can keep the iterator style of above:

std::vector< boost::variant<int, bool, char> > data;
computeValues(42, std::back_inserter(data));
like image 112
Johannes Schaub - litb Avatar answered Dec 01 '22 21:12

Johannes Schaub - litb