【问题标题】:Need decay in perfect forwarding完美转发需要衰减
【发布时间】:2018-08-27 11:23:03
【问题描述】:

我不明白为什么以下代码无效。

#include <type_traits>
#include <tuple>

template<typename... Ts>
void funka( std::tuple<Ts...>&& v ) {    
}

template<typename T>
void funkb( T&& v ) {
    funka( std::forward<T>( v ) );
}

void funk() {
    auto tup = std::tuple<int,int>( 1, 2 );
    funkb( tup );
}

失败并出现此错误:

<source>: In instantiation of 'void funkb(T&&) [with T = std::tuple<int, int>&]':
<source>:24:16:   required from here
<source>:10:10: error: cannot bind rvalue reference of type 'std::tuple<int, int>&&' to lvalue of type 'std::tuple<int, int>'
     funka( std::forward<T>( v ) );
     ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~

如果我 forward 衰减,它将编译。

template<typename T>
void funkb( T&& v ) {
    funka( std::forward<std::decay_t<T>>( v ) );
}

所以问题是。为什么那不是有效的代码?在我看来,funkbfunka 的结果参数类型似乎是相同的。

提前致谢

【问题讨论】:

  • && 在 funka 中是一个右值引用,而在 funkb 中类似的 && 是一个转发引用。

标签: c++ perfect-forwarding


【解决方案1】:

为什么那不是有效的代码?

funkb( tup ) 调用中,tup 是一个左值。由于转发引用推导规则,funka中的参数v的类型推导为std::tuple&lt;int, int&gt;&amp;

std::forward&lt;std::tuple&lt;int, int&gt;&amp;&gt;( v ) 不会移动 v - 它仍然是一个左值

左值不绑定到右值引用


如果我转发衰减,它会编译。

std::decay_t 删除所有 cv 限定符和引用。它将您的 forward 调用更改为:std::forward&lt;std::tuple&lt;int, int&gt;&gt;( v )

std::forward 以非引用或右值引用 作为其模板参数调用时,它将移动v

【讨论】:

    【解决方案2】:

    如果您使用衰减并将右值传递给funkb,则衰减不会执行任何操作,因为该类型已经“衰减”(即T)。

    如果你传入一个左值,那么转发引用的类型是T&amp;,当你衰减它时,你会得到T。这意味着std::forward 的结果在这两种情况下都是右值。

    现在代码在没有衰减的情况下无效,因为funka 采用右值引用,并且您将左值传递给funkb,然后您将其转发(保留值类别)。你基本上是在做

    int a;
    int&& b = a;
    

    如您所见,通过衰减,您将始终获得一个右值,它可以绑定到一个右值引用。

    【讨论】:

      猜你喜欢
      • 2020-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多