【问题标题】:Is it possible to avoid repetition of std::move() on a tuple?是否可以避免在元组上重复 std::move() ?
【发布时间】:2016-01-28 19:43:39
【问题描述】:

假设我有一个元组和一个函数:

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

所以在辅助函数中,我将元组展开为参数:

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

它有效,但我想避免多次重复std::move。天真的解决方案,例如:

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

显然不起作用,因为 rt 是lvalue。那么有没有办法避免每个std::get重复std::move()多次?

【问题讨论】:

  • 真正避免重复,请使用众多“爆炸元组”实现中的一种,它可以让您将一个元组“爆炸”成匹配的函数调用的参数。所谓的感谢(AFAIK)关于该主题的祖父演示,The Way of the Exploding Tuple。你所需要的只是可变参数模板,但如果你有 C++14,你可以获得更简单的实现,例如,Exploding Tuple in C++14

标签: c++ c++11 move-semantics rvalue-reference stdtuple


【解决方案1】:

您可能想使用std::integer_sequence

它在 C++14 中可用,但可以用 C++11 实现:https://github.com/serge-sans-paille/pythran/blob/master/pythran/pythonic/include/utils/seq.hpp

多亏了这个,你需要一个额外的功能,但你避免了这种重复:

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

变成

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>{});
}

但是你必须为此创建一个辅助函数。

【讨论】:

  • 当你没有指定类型时,你必须使用std::make_index_sequence(默认使用size_t)而不是std::make_integer_sequence。我相信你不需要typename 也不需要::type()
  • 包展开后t不会移动多次吗?
  • @0x499602D2:它将多次传递给std::move,但std::get&lt;N&gt; 上的std::tuple 右值引用将返回对第N 个元素的右值引用。当someFunction 调用在unroll_impl 中评估时, 将被移动。简单地说,std::get&lt;I&gt;( std::move( t ) ) 正好等价于std::move( std::get&lt;I&gt;( t ) )
【解决方案2】:

从语义上讲,您无法避免 std::move。要获得右值,您需要没有某事物的名称(因此您不能两次引用它)或使用std::move 去除名称。 t 有名称,但要将 unique_ptr 传递给函数调用,您需要它没有名称。

例如,您可以通过将展开更改为(更惯用的?)来看到这一点

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

任何解决方案都将涉及每个 unique_ptr 函数参数上的 std::move(),或者调用另一个返回右值或右值引用的函数。

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() );
}

【讨论】:

    猜你喜欢
    • 2012-09-15
    • 1970-01-01
    • 2015-03-28
    • 2013-09-17
    • 2016-10-27
    • 2017-08-21
    • 1970-01-01
    • 2021-08-16
    相关资源
    最近更新 更多