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