参考折叠规则未按预期应用?
Reference collapsing rules not applying as expected?
我正在刷新我对 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
。因此,没有对 collapse 的引用,静态转换会产生 int&&
.
如果调用的函数是 T&& fwd(T&& t)
(即如果不存在更好的匹配重载),那么您对引用折叠的解释是正确的(除了参数 int& &&
也折叠 int&
) 并且 return 类型确实是左值引用。
实际上,没有发生引用崩溃。需要注意的相关功能模板,即选中的是:
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&& &&
).
我正在刷新我对 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
。因此,没有对 collapse 的引用,静态转换会产生 int&&
.
如果调用的函数是 T&& fwd(T&& t)
(即如果不存在更好的匹配重载),那么您对引用折叠的解释是正确的(除了参数 int& &&
也折叠 int&
) 并且 return 类型确实是左值引用。
实际上,没有发生引用崩溃。需要注意的相关功能模板,即选中的是:
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&& &&
).