C++ 两个超负荷的std::forward如何工作?

C++ 两个超负荷的std::forward如何工作?,c++,c++11,forward-declaration,C++,C++11,Forward Declaration,我在std库中发现了std::forward的以下实现: // TEMPLATE FUNCTION forward template<class _Ty> inline constexpr _Ty&& forward( typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT { // forward an lvalue as either an lvalue or an rvalue

我在std库中发现了std::forward的以下实现:

// TEMPLATE FUNCTION forward
template<class _Ty> inline
constexpr _Ty&& forward(
    typename remove_reference<_Ty>::type& _Arg) _NOEXCEPT
{   // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}

template<class _Ty> inline
constexpr _Ty&& forward(
    typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{   // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
//模板函数转发
模板内联
constexpr\u Ty和forward(
typename删除\u引用::类型和参数)\u无例外
{//将左值作为左值或右值转发
返回(静态_cast(_Arg));
}
模板内联
constexpr\u Ty和forward(
typename remove_reference::type&&_Arg)_NOEXCEPT
{//将右值作为右值转发
静态断言(!is_lvalue_reference::value,“错误的前向调用”);
返回(静态_cast(_Arg));
}
第一个函数显然有效,但第二个函数我找不到有用的例子。 如果我尝试这样做:

template<class _Ty> inline
constexpr _Ty&& my_forward(
   typename std::remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{   // forward an rvalue as an rvalue
   static_assert(!std::is_lvalue_reference<_Ty>::value, "bad forward call");
   return (static_cast<_Ty&&>(_Arg));
}

template<typename T>
T getRValue()
{
    return std::remove_reference<T>::type{};
}

template<typename T>
void setValue(T && i)
{
   my_forward<T>(getRValue<T>());
}

int main()
{
    int i = 1;
    setValue(i);
}
template<typename T>
void precompute(T & t)
{
   std::cout << "lvalue reference";
}

template<typename T, 
         std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
   std::cout << "rvalue reference";
}

template<typename T>
void calculate(T && t)
{
   precompute(std::move(t)); // Every time called precompute(T && t)
}
模板内联
constexpr\u Ty和my\u forward(
typename std::remove_reference::type&&_Arg)\u NOEXCEPT
{//将右值作为右值转发
静态断言(!std::is_lvalue_reference::value,“错误的前向调用”);
返回(静态_cast(_Arg));
}
模板
T getRValue()
{
返回std::remove_reference::type{};
}
模板
无效设置值(T&&i)
{
my_forward(getRValue());
}
int main()
{
int i=1;
设定值(i);
}
为了检查何时调用第二个函数,我得到了错误:

Error   C2664   '_Ty my_forward<T>(int &&) noexcept': cannot convert argument 1 from 'int' to 'int &&'
错误C2664'\u Ty my\u forward(int&&)noexcept':无法将参数1从'int'转换为'int&'
有人知道在哪种情况下调用第二个重载函数(用我的术语来说是my_forward)吗? 或者是一个很好的例子? 顺便说一下,我的编译器是MSVC 2015

谢谢大家的帮助

int bad_forward_call(){
int bad_forward_call() {
  return std::forward<int&>(7);
}
返回std::转发(7); }
这将调用该版本

注意,我将右值作为左值转发。不允许


如果
T
是引用类型,则您的
getRValue
无法获取右值。

我发现调用此函数的情况:

my_forward<int&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it won't compile 'cause we try convert rvalue to lvalue

my_forward<int&&>(8); // This calls forward(typename remove_reference<_Ty>::type&& _Arg)
But it compiles successfully
my_forward(8);//这将调用forward(typename remove_reference::type&&u Arg)
但它无法编译,因为我们尝试将右值转换为左值
我的前锋(8);//这将调用forward(typename remove_reference::type&&u Arg)
但它编译成功了
如果对某人有用,std::forward的目的是将操作转发到另一个类或函数

考虑以下示例:

template<typename T>
void precompute(T & t)
{
   std::cout << "lvalue reference";
}

template<typename T, 
         std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
   std::cout << "rvalue reference";
}

template<typename T>
void calculate(T && t)
{
   precompute(t); // Every time called precompute(T & t)
}
模板
无效预计算(T&T)
{
标准::cout
无效预计算(T&T)
{
标准::cout
无效计算(T&T)
{
预计算(std::move(t));//每次调用预计算(t&&t)
}
正如你所看到的,我们有一个问题!!两个例子都不能让我们满意

在第一个示例中,每次都将调用左值函数,并且无法使用右值首先调用

在第二个示例中,每次都将调用rvalue函数,并且无法使用lvalue首先调用

解决方案是将决策转发给被调用函数:

template<typename T>
void precompute(T & t)
{
   std::cout << "lvalue reference";
}

template<typename T, 
         std::enable_if_t<!std::is_reference<T>::value, bool> = true>
void precompute(T && t)
{
   std::cout << "rvalue reference";
}

template<typename T>
void calculate(T && t)
{
   precompute(std::forward<T>(t)); // Will be called either precompute(T & t) or precompute(T && t) depends on type of t
}
模板
无效预计算(T&T)
{
标准::cout
无效预计算(T&T)
{

std::cout注释说“将右值作为右值转发”,但您将右值作为左值转发(并且还有未定义行为的情况)。这不是函数编写的目的。@Johannes Schaub:为什么?getRValue()提供prvalue,它可以作为my_forward的参数。您能给出一个有用的示例,如我的示例中所示,将my_forward用于右值吗?@DenisKotov:“getRValue()提供prvalue”是吗?它返回一个
T
,但是
T
可以是一个引用。因此,它可能是一个左值。@Johannes Schaub:很抱歉不正确。它是xvalue,但不是左值,因为函数的返回值可以重用,但它没有名称Yet这也很相关-不,这个版本不调用那个版本。它甚至不编译这是由于静电引起的assert@DenisKotov在那个版本中有一个
静态断言
,我相信我正在点击它。