I am trying avoid output arguments in my functions. The old function is:
void getAllBlockMeanError(
const vector<int> &vec, vector<int> &fact, vector<int> &mean, vector<int> &err)
Here vec is input argument, fact, mean and err are output argument. I tried to group output argument to one tuple:
tuple< vector<int>, vector<int>, vector<int> >
getAllBlockMeanErrorTuple(const vector<int> &vec)
{
vector<int> fact, mean, err;
//....
return make_tuple(fact, mean, err);
}
Now I can call the new function with:
tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec);
It looks cleaner to me. While I have a question, how does equal assignment of tie(fact, mean, err) work? Does it do a deep copy or a move? Since fact, mean and err inside getAllBlockMeanErrorTuple will be destroyed, I hope it is doing a move instead of a deep copy.
Vectors as return valuesYes, functions in C++ can return a value of type std::vector .
A 2D vector of tuples or vector of vectors of tuples is a vector in which each element is a vector of tuples itself. Although a tuple may contain any number of elements for simplicity, a tuple of three elements is considered. Here, dataType1, dataType2, dataType3 can be similar or dissimilar data types.
While C++ does not have an official way to return multiple values from a function, one can make use of the std::pair , std::tuple , or a local struct to return multiple values.
A tuple is an object that can hold a number of elements and a vector containing multiple number of such tuple is called a vector of tuple. The elements can be of different data types.
You function signature is tuple< vector<int>, vector<int>, vector<int> >, which is a temporary and the elements are eligible to be moved, so
std::tie(fact, mean, err) = getAllBlockMeanErrorTuple(vec)
should move-assign fact, mean, and err.
Here's a sample program for you to see for yourself (demo):
#include <iostream>
#include <vector>
#include <tuple>
struct A
{
A() = default;
~A() = default;
A(const A&)
{
std::cout << "Copy ctor\n";
}
A(A&&)
{
std::cout << "Move ctor\n";
}
A& operator=(const A&)
{
std::cout << "Copy assign\n";
return *this;
}
A& operator=(A&&)
{
std::cout << "Move assign\n";
return *this;
}
};
std::tuple<A, A> DoTheThing()
{
A first;
A second;
return std::make_tuple(first, second);
}
int main()
{
A first;
A second;
std::tie(first, second) = DoTheThing();
}
Output:
Copy ctor
Copy ctor
Move assign
Move assign
Note that the function had to create copies of the vectors for returning the tuple, which may not be what you want. You may want to std::move the elements into std::make_tuple:
return make_tuple(std::move(fact), std::move(mean), std::move(err));
Here's the same example as above, but with std::move used in make_tuple
Note that with C++17's Structured Bindings, you can forget about using std::tie at all, and lean more on auto (Thanks, @Yakk):
auto[fact, mean, err] = getAllBlockMeanErrorTuple(vec);
The early implementations of the C++17 standard for clang (3.8.0) and gcc (6.1.0) don't support it yet, however it seems there is some support in clang 4.0.0: Demo (Thanks, @Revolver_Ocelot)
You'll notice that the output with structured bindings changes to:
Move ctor
Move ctor
Indicating that they take advantage of copy-elision, which saves additional move operations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With