如cplusplus.com所述,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;
std::forward
的典型用法是在将参数传递给其他函数时保留 rvalueness。让我们通过一个例子来说明:
void overloaded(int &) { std::cout << "lvalue"; }
void overloaded(int &&) { std::cout << "rvalue"; }
template <typename T>
void fwd(T && t)
{
overloaded(std::forward<T>(t));
}
当我们调用
fwd(0)
时,T
推导为 int
(t
的类型为 int &&
)。然后我们调用 std::forward<int>(t)
。该调用的结果是类型为 int &&
的表达式,因此选择了第二个版本的 overloaded
函数,并将 "rvalue" 打印到标准输出中。当我们调用
fwd(i)
(其中 i 是某些 int 变量)时,T
推导为 int&
(t
的类型为 int &
)。然后我们调用 std::forward<int&>(t)
。该调用的结果(应用引用折叠规则后)是类型为 int &
的表达式,因此选择了第一个版本的 overloaded
函数,并将 "lvalue" 打印到标准输出中。在这两种情况下,我们使用
std::forward
的第一个重载(采用 typename remove_reference<T>::type& arg
)。这是因为即使 t
的类型为 int &&
,它也会绑定到左值引用(因为类型为“rvalue reference to something”的命名变量本身是左值,而左值无法绑定到右值引用)。
问题 1:
std::forward
的第二个重载是用于什么的?您能想到一些实际的例子,使用采用 rvalue 引用的 arg
的重载吗?
问题 2:
cplusplus.com 上说:
我对此有所疑虑,因为我相信它是错误的。当我们尝试从第一个重载的Both signatures return the same as:
static_cast<decltype(arg)&&>(arg)
std::forward
返回时,会出现编译错误。当使用
int
右值调用fwd
时,它将使用T = int
调用std::forward
的第一个重载。然后,decltype(arg)
将变为int&
,因此static_cast<decltype(arg)&&>(arg)
将折叠为static_cast<int&>(arg)
。但是返回类型为int &&
,因此我们会遇到编译错误:cannot bind ‘std::remove_reference<int>::type {aka int}’ lvalue to ‘int&&’
两个重载版本的std::forward
都应该返回static_cast<T&&>(arg)
。我说得对吗?
你认为cplusplus.com上引用的这段话是错误的吗?
const
和const_cast
散布在其中。 - Yakk - Adam Nevraumontcplusplus.com
不是cppreference
。cppreference.com
是cppreference
。要区分清楚它们之间的差异。 - Nawaz