我认为转发引用是完美转发的一部分。我试着向别人解释它,却意识到我不知道:它能把T&&
推断为某种非参考类型吗?
#include <type_traits>
#include <utility>
template <typename Expected>
void checkDeduction(auto&& x) {
static_assert(std::is_same_v<Expected, decltype(x)>);
}
int main() {
checkDeduction<int&&>(1);
const volatile int x = 0;
checkDeduction<const volatile int&>(x);
checkDeduction<const volatile int&&>(std::move(x)); // Weird, but whatever.
// Is there anything for which checkDeduction<int>(foo) will compile?
}
https://godbolt.org/z/cr8K1dsKa
我认为答案是"不",它总是一个右值引用或左值引用。
我认为这是因为如果f
转发到g
:
decltype(auto) f(auto&& x) { return g(std::forward<decltype(x)>(x)); }
不是f
与g
具有相同的签名,而是f
是用f
的调用者提供的值类别编译的,所以如果g
取int
,而你调用f(1)
,那么f
得到int&&
并将其转发给g
。在调用g
时,int&&
衰变成int
。
显然T&&
是某种引用;有趣的问题是T
是否总是被推断为引用类型。答案是不:如果参数是类型为U
的左值,则T
将是U&
;如果参数是类型为右值,则T
将只是U
。
U
和xvalue被推断为U&&
(它仍然会被"外部"引用操作符崩溃)。然而,判断是,这种区别并不重要,至少不足以证明在任何地方创建额外的模板专门化是合理的。
仍然可以写f<X&&>(…)
力转发引用的模板形参是一个右值引用,尽管这通常不会完成任何事情。