Slava
Slava

Reputation: 44258

Is it possible to avoid repetition of std::move() on a tuple?

Let's say I have a tuple and a function:

typedef std::tuple< std::unqiue_ptr<int>, std::unqiue_ptr<char> > SomeTuple;          
void someFunction( std::unqiue_ptr<int>, std::unqiue_ptr<char> );

so in a helper function I am unrolling tuple into arguments:

void unroll( SomeTuple &t )
{
    someFunction( std::get<0>( std::move( t ) ), std::get<1>( std::move( t ) ) );
}

It works, but I want to avoid repeating of std::move multiple times. Naive solutions like:

void unroll( SomeTuple &t )
{
    auto &&rt = std::move( t );
    someFunction( std::get<0>( rt ), std::get<1>( rt ) );
}

obviosly does not work, as rt is a lvalue. So is there a way to avoid repeating std::move() multiple times for each std::get?

Upvotes: 0

Views: 357

Answers (2)

TBBle
TBBle

Reputation: 1476

Semantically, you can't avoid the std::move. To get an rvalue, you need to either not have a name for something (so you can't refer to it twice) or strip the name with std::move. And t has a name, but to pass a unique_ptr to a function call, you need it to not have a name.

You can see this for example by changing unroll to the (more idiomatic?)

void unroll( SomeTuple &t )
{
  someFunction( std::move( std::get<0>( t ) ), std::move( std::get<1>( t ) ) );
}

Any solution is going to involve either a std::move() on each unique_ptr function parameter, or a call to another function that returns an rvalue or rvalue reference.

void unroll( SomeTuple &t )
{
    auto get0 = [&]()->std::unique_ptr<int>&& { return std::move(std::get<0>(t)); };
    auto get1 = [&]()->std::unique_ptr<char> { return std::move(std::get<1>(t)); };

    someFunction( get0(), get1() );
}

Upvotes: 1

P. Brunet
P. Brunet

Reputation: 204

You may want to use std::integer_sequence

It is available from C++14 but can be implemented with C++11 : https://github.com/serge-sans-paille/pythran/blob/master/pythran/pythonic/include/utils/seq.hpp

Thanks to this, you need an extra function but you avoid this repetition :

void unroll( SomeTuple &t )
{
    someFunction( std::get<0>( std::move( t ) ), std::get<1>( std::move( t ) ) );
}

becomes

template<size_t ...I>
void unroll_impl( SomeTuple &t , std::integer_sequence<I...>)
{
    someFunction( std::get<I>( std::move( t ) )...);
}

void unroll( SomeTuple &t )
{
    unroll_impl( t, std::make_index_sequence<2>{});
}

But you have to create an helper function for this.

Upvotes: 5

Related Questions