问朋友:
为什么以下代码中的std::forward
将参数c
强制转换为右值?
template <typename T>
void f (T& c) {
using value_type = typename std::remove_reference_t<T>;
std::vector<value_type> v;
// debugger reveals: push_back( T&& value ) is called here
v.push_back(std::forward<T>(c));
}
请注意,c
不是此处的通用/转发参考。我知道这个函数最有可能更有用,如果它实际上是,但好奇都是一样的。
要了解这种情况,您必须了解转发引用的工作原理。给定一个定义
template <typename T>
void foo(T&& t) {}
当你写的东西像
some_type some_object;
foo(some_object);
模板演绎推论T
是some_type&
。现在参数t
的类型为some_type& &&
。由于您不能引用引用,因此应用reference collapsing规则并将some_type& &&
折叠为some_type&
。
相反,如果你写了类似的东西
some_type some_object;
foo(std::move(some_object));
模板演绎推论T
是some_type
。现在参数t
的类型为some_type&&
。这是一个完全有效的类型,因此没有参考折叠。
现在我们到达std::forward
。所有std::forward<U>
都将其参数投射到U&&
。如果U
是some_type
,如上面第二种情况那样,参数将被强制转换为some_type&&
。它仍然是一个右值参考。如果U
是some_type&
,就像上面的第一个案例那样,再次执行参考折叠,并且some_type& &&
变成some_type&
。所以std::forward
返回一个左值引用。
因此,对原始问题的最终答案是std::forward
的返回类型仅取决于作为std::forward
的模板参数传递的类型。由于qzxswpoi在您的情况下将始终推断为非引用类型,因此T
将始终返回rvalue-reference。
std::forward
相当于std::forward<T>(c)
。
如果static_cast<T&&>(c)
是转发引用,那么这允许左值作为左值转发,因为T&&
将被推导为左值引用类型,并且T
将是引用 - 折叠规则的相同左值引用类型。在您的情况下,T&&
不是转发参考,所以这不起作用。
好吧,T&&
的定义是将std::forward<T>(x)
转换为x
类型。如果你传递一个非参考作为参数,你将获得一个右值参考T&&
。由于您的T&&
不能是引用类型(您不能引用引用),因此它必须是非引用类型。