根据函数模板参数推导规则,T&& <=> X& 可推出 T <=> X& 。
forward
再次单步调用进入forward函数实体所在的源码第4行或第9行。
先尝试匹配源码第4行的forward函数,_Tp <=> X& 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type& <=> X& 。形参 __t 与实参 t 类型相同,因此函数匹配成功。再尝试匹配源码第9行的forward函数,_Tp <=> X& 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type&& <=> X&& 。形参 __t 与实参 t 类型不同,因此函数匹配失败。由10与13可知7单步调用实际进入的是源码第4行的forward函数。static_cast<_Tp&&>(__t) <=> static_cast
再次单步调用将进入测试代码第5行的inner(const X&) 版本,左值参数转发成功。然后我们来分析 outer(X()) 这种调用forward函数转发右值参数的情况。模拟单步调用来到测试代码第8行,T&& <=> X&&, t <=> X() 。根据函数模板参数推导规则,T&& <=> X&& 可推出 T <=> X 。
forward
typename std::remove_reference<_Tp>::type& <=> X& 。形参 __t 与实参 t 类型相同,因此函数匹配成功。再尝试匹配源码第9行的forward函数,_Tp <=> X 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type&& <=> X&& 。形参 __t 与实参 t 类型不同,因此函数匹配失败。由25与28可知22单步调用实际进入的仍然是源码第4行的forward函数。
static_cast<_Tp&&>(__t) <=> static_cast
再次单步调用将进入测试代码第6行的inner(X&&) 版本,右值参数转发成功。
由17和32可知源码中std::forward函数的具体实现符合标准,
因为无论用左值a还是右值X()做参数来调用带有右值引用参数的函数模板outer,
只要在outer函数内使用std::forward函数转发参数,
就能保留参数的左右值属性,从而实现了函数模板参数的完美转发。