问题描述
我正在刷新关于C ++完美转发工作方式的记忆。我意识到,出于某种原因(例如,在处理实际上是左值的右值引用时),对std::forward
的调用被迫提供一个显式模板参数,但是当对实际代码进行完整性检查时,我对此感到惊讶(有点相关)方案:
#include <iostream>
#include <utility>
#include <type_traits>
template<class T>
T&& fwd(T& t) {
return static_cast<T&&>(t);
}
template<class T>
T&& fwd(T&& t) {
return static_cast<T&&>(t);
}
int main()
{
int lnum = 3;
if (std::is_rvalue_reference<decltype(fwd(lnum))>::value)
std::cout << "It's rref." << std::endl; // this get's printed on screen
else
std::cout << "It's lref." << std::endl;
return 0;
}
如果我理解引用正确折叠(并且我相信是这样),则类型推导应如下所示:
int& && fwd(int& & t) {
return static_cast<int& &&>(t);
}
导致
int& fwd(int& t) {
return static_cast<int&>(t);
}
显然不是这样。我在这里想念什么?
解决方法
首先,被调用的函数为T&& fwd(T& t)
。因此,没有转发参考参数。参数是左值引用,推导的T
是int
。因此,没有崩溃的引用,并且静态类型转换产生int&&
。
如果被调用函数为T&& fwd(T&& t)
(即,不存在更好的匹配重载),那么您对引用折叠的解释将是正确的(参数int& &&
除外)也折叠int&
),返回类型的确是左值引用。
实际上,没有引用崩溃发生。要注意的相关功能模板(即所选的一个)是:
template<class T>
T&& fwd(T& t) { // <-- not a forwarding reference
return static_cast<T&&>(t);
}
请注意,此功能模板没有没有 转发引用 –函数参数t
只是左值引用( T& t
。
T
模板参数推导为 int
–不是int&
–因为t
不是转发引用,而只是左值引用。如果仅在上面的函数模板中将T
替换为int
,那么您将获得:
template<class T>
int&& fwd(int& t) {
return static_cast<int&&>(t);
}
不应用引用折叠,因为此处没有这样的事情,否则它们最终会成为对引用的引用(例如int& &&
或int&& &&
)。