在完美转发中需要衰减

时间:2018-08-27 11:23:03

标签: c++ perfect-forwarding

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

#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的最终参数类型是相同的。

预先感谢

2 个答案:

答案 0 :(得分:4)

  

为什么那是无效的代码?

funkb( tup )调用中,tup左值。由于转发参考推导规则,v中参数funka的类型推导为std::tuple<int, int>&

std::forward<std::tuple<int, int>&>( v )不会移动v-它仍然是左值

左值不绑定到右值引用


  

如果我向前衰减,它将进行编译。

std::decay_t删除所有简历限定符和引用。它将您的forward调用更改为:std::forward<std::tuple<int, int>>( v )

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

答案 1 :(得分:3)

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

但是,如果传入一个左值,则转发引用的类型为T&,而衰减该引用时,则得到T。这意味着在两种情况下,std::forward的结果都是右值。

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

int a;
int&& b = a;

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