编译器如何知道必须调用std :: forward函数的哪个重载?

M. *_* E. 6 c++ templates perfect-forwarding c++11

以下签名声明为std::forward重载:

template<class T> T&& forward(typename remove_reference<T>::type& arg) noexcept;
template<class T> T&& forward(typename remove_reference<T>::type&& arg) noexcept;
Run Code Online (Sandbox Code Playgroud)

现在,考虑以下模板函数:

template<class T> T&& foo_as_always(T&& t)
{
    return std::forward<T>(t);
}
Run Code Online (Sandbox Code Playgroud)

如果我写:

int i = 0;
foo_as_always(i);
Run Code Online (Sandbox Code Playgroud)

然后这就是编译器实例化的foo_as_always方式T = int&:

int& foo_as_always(int& t)
{
    // Does it call the first signature of std::forward(int&)
    return std::forward<int&>(t);
}
Run Code Online (Sandbox Code Playgroud)

如果我写:

foo_as_always(0);
Run Code Online (Sandbox Code Playgroud)

那么编译器实例foo_as_alwaysT = int:

int&& foo_as_always(int&& t)
{
    // Does it call the second signature of std::forward(int&&)?
    return std::forward<int>(t);
}
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,t变量都是任何表达式中的l值.编译器如何知道std::forward必须调用函数的哪个重载?

Rei*_*ica 6

因为你明确地提供了模板参数(你提供的<T>); 没有类型扣除.

在通话中foo_as_always(i);,iT推导出的左值int &,这是你提供的std::forward.

在通话中foo_as_always(0);,0是一个rvalue,因此T推断出来int,这也是你提供的std::forward.

在这两种情况下,它最终会调用第一个重载,当然,因为它t是一个左值,正如你所说.但是返回类型不同 - 在第一种情况下,它是int& &&,所以int&,在第二种情况下,它是int &&.