Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function return a tuple made of vectors

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.

like image 397
Hao Shi Avatar asked Sep 15 '16 14:09

Hao Shi


People also ask

Can functions return vectors?

Vectors as return valuesYes, functions in C++ can return a value of type std::vector .

Can you have a vector of tuples?

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.

How can I return multiple values from a vector in C++?

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.

Are tuples and vectors the same?

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.


1 Answers

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.

like image 175
AndyG Avatar answered Nov 03 '22 00:11

AndyG