【问题标题】:How to forward unique_ptr with tuple?如何用元组转发 unique_ptr?
【发布时间】:2015-03-16 15:52:47
【问题描述】:

想象一个期望对 std::unique_ptr 进行右值引用的函数。

void foo(std::unique_ptr<int>&& a);

在我的真实示例中,参数不止一个,因此我决定使用右值引用的std::tuple&lt;T&amp;&amp;&gt; 将参数转发给它 - 所以std::forward_as_tuple

void forward_to_foo(std::tuple<std::unique_ptr<int>&&>&& t);
int main() {
   forward_to_foo(std::forward_as_tuple(std::make_unique<int>(8)));
}

目前一切正常。

当我想“解包”这个元组时出现问题

void forward_to_foo(std::tuple<std::unique_ptr<int>&&>&& t)
{
   foo(std::get<0>(t));
}

我在使用 c++14 的 gcc4.9 上遇到了这个错误:

error: cannot bind 'std::unique_ptr<int>' lvalue to 'std::unique_ptr<int>&&'
    foo(std::get<0>(t));

我的问题:这里有什么问题?为什么右值引用元组中的std::get&lt;I&gt;(t)返回左值?

【问题讨论】:

  • 因为t 是一个左值。使用std::get&lt;0&gt;(std::move(t));
  • std::tuple&lt;std::unique_ptr&lt;int&gt;&amp;&amp;&gt; t = std::forward_as_tuple&lt;std::make_unique&lt;int&gt;(8)); - 这给出了一个悬空引用,所以是 UB。
  • 您能否发布没有不相关语法错误的代码?简化,然后在简化的代码中实际重现问题。如果您简化为有不同问题的代码,或者没有您的问题,那么代码通常比无用更糟糕。 MCVE 可能会有所帮助。
  • @ecatmur - 我希望我修好了。
  • @piotr 发布的代码中仍然存在不相关的语法错误。请发布实际产生您所询问的错误的代码。将其放入编译器,然后编译。你的括号甚至不匹配!

标签: c++ c++11 tuples unique-ptr


【解决方案1】:

这里有什么问题?

您需要 std::move 才能从 左值 表达式中移动:

foo(std::move(std::get<0>(t)));

为什么右值引用元组中的std::get&lt;I&gt;(t)返回左值?

因为它返回一个对元组元素的 lvalue 引用。通常,返回 lvalue 引用的函数的结果是 lvalue,因为它表示现有对象而不是临时对象。

【讨论】:

  • 是的,你是对的;我过于简化了我的例子。我的真实示例需要将元组作为 const 左值引用传递 - 因此我不能这样做 std::move。这个const reference 是因为我需要使用一些遗留库。但无论如何,你回答了这个问题。我将创建一个新的。
  • 所以这很接近。然而,移动应该在t 上而不是在整个get 表达式上:std::get<0>(std::move(t))。一旦t 作为右值转发,get 就会返回一个右值。上面的构造有一个“问题”,即使t 包含左值引用,std::move 仍然会将它们移出。对于std::get&lt;N&gt;(std::move(t)),只有值和右值引用作为右值引用返回。这往往更安全,并且导致的错误通常表明其他地方存在逻辑问题,至少在转发代码中是这样。
  • 是的,我误读了这个问题,并没有发现到处都是参考资料。我可能应该删除答案;在星期一有太多的间接需要考虑。
猜你喜欢
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 1970-01-01
  • 2017-05-12
  • 2019-02-12
  • 1970-01-01
  • 2018-12-15
  • 1970-01-01
相关资源
最近更新 更多