【问题标题】:C++11 std::forward_as_tuple and std::forwardC++11 std::forward_as_tuple 和 std::forward
【发布时间】:2014-10-15 04:21:32
【问题描述】:

当我将函数参数用作std::forward_as_tuple 的参数时,我应该std::forward 吗?

template<class ... List>
void fn(List&& ... list){
   // do I need this forward?
   call_fn( forward_as_tuple( forward<List>(list)... ) );  
}

我知道它们将被存储为右值引用,但我还有什么需要考虑的吗?

【问题讨论】:

    标签: c++ templates c++11 tuples perfect-forwarding


    【解决方案1】:

    您必须使用std::forward 才能将参数的值类别保留为fn()。由于参数在fn 中具有名称,它们是左值,没有std::forward,它们将始终按原样传递给std::forward_as_tuple

    可以使用following example 来演示差异:

    template<typename T>
    void bar2(T&& t)
    {
        std::cout << __PRETTY_FUNCTION__ << ' '
                   << std::is_rvalue_reference<decltype(t)>::value << '\n';
    }
    
    template<typename T>
    void bar1(T&& t)
    {
        std::cout << __PRETTY_FUNCTION__ << ' '
                  << std::is_rvalue_reference<decltype(t)>::value << '\n';
        bar2(std::forward<T>(t));
        bar2(t);
    }
    

    bar1 总是将它的参数传递给bar2,一次使用std::forward,一次没有。现在让我们用一个左值和一个右值参数来调用它们。

    foo f;
    bar1(f);
    std::cout << "--------\n";
    bar1(foo{});
    

    输出:

    void bar1(T&&) [with T = foo&] 0
    void bar2(T&&) [with T = foo&] 0
    void bar2(T&&) [with T = foo&] 0
    --------
    void bar1(T&&) [with T = foo] 1
    void bar2(T&&) [with T = foo] 1
    void bar2(T&&) [with T = foo&] 0
    

    从输出中可以看出,在这两种情况下,在不使用std::forward 的情况下,参数都作为左值传递给bar2

    【讨论】:

    • call_fn(std::forward_as_tuple&lt;List...&gt;(list...)); 会做什么?
    • @LogicStuff 我认为这不会编译。假设包只有一个类型,T。现在,如果将右值T 传递给外部fn,那么List 将被推导出为T,所以你会写call_fn(std::forward_as_tuple&lt;T&gt;(t));。但是forward_as_tuple 会想要一个对t 的右值引用作为它的参数。如果你传递 fn 一个左值,它的工作原理是一样的。
    【解决方案2】:

    是的,你几乎肯定想在这里使用std::forward,这是假设list 中的参数在调用call_fn 之后没有使用。 这是std::forward 的一个典型用例,您想练习完美转发的语义

    std::forward preserves the value category 的参数(即左值作为左值,右值作为右值)。 std::forward_as_tuple 反过来也会做同样的事情,就好像 std::tuple&lt;List&amp;&amp;...&gt;(std::forward&lt;List&gt;(list)...) 被调用了一样。

    关于“存储为右值引用”的注释。并不是参数包中的参数List 都是右值引用(它们可能是),而是List 在这种情况下被推导出来,因此引用折叠将适用并且推导的类型可能是右值引用或左值引用。在创建std::tuple 期间,您希望维护/保留这种区别。

    【讨论】:

      【解决方案3】:

      是的,如果您想保留完美的转发语义。在您的示例中:

      template<class ... List>
      void fn(List&& ... list)
      

      List&amp;&amp; 类型,其中List 实际上是一个模板参数,是一个Universal Reference,而不是一个右值引用。因此,您应该将它们std::forward 传递给std::forward_as_tuple 函数,否则在std::forward_as_tuple 内部,由于引用折叠,传递给fn 的右值引用将作为左值引用可见。

      【讨论】:

        猜你喜欢
        • 2014-04-15
        • 1970-01-01
        • 1970-01-01
        • 2014-10-09
        • 2016-07-08
        • 1970-01-01
        • 2021-08-08
        • 2014-06-12
        • 1970-01-01
        相关资源
        最近更新 更多