我不明白为什么以下代码无效。
#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 ) );
}
问题是。为什么那是无效的代码?在我看来,funkb
和funka
的最终参数类型是相同的。
预先感谢
答案 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;
如您所见,通过衰减,您将始终获得一个右值,该右值可以绑定到右值引用。