使用std :: forward和非转发的普通旧引用

时间:2017-12-15 23:19:14

标签: c++ c++11 move-semantics perfect-forwarding

要求朋友:

为什么以下代码中的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不是通用/转发参考。我知道这个函数最有可能更有用,如果它实际上是,但好奇都一样。

3 个答案:

答案 0 :(得分:2)

std::forward<T>(c)相当于static_cast<T&&>(c)

如果T&&是转发引用,则允许左值作为左值转发,因为T将被推导为左值引用类型,T&&将是相同的左值引用按引用 - 折叠规则键入。在您的情况下,T&&不是转发引用,因此这不起作用。

答案 1 :(得分:1)

嗯,std::forward<T>(x)的定义是将x转换为T&&类型。如果你传递一个非参考作为参数,你将得到一个右值引用T&&。由于您的T不能是引用类型(您不能引用引用),因此它必须是非引用类型。

答案 2 :(得分:1)

要了解这种情况,您必须了解转发引用的工作原理。给出像

这样的定义
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&&。如果Usome_type,则与上面的第二种情况一样,参数将转换为some_type&&。它仍然是一个右值参考。如果Usome_type&,与上述第一种情况相同,则会再次执行参考折叠,some_type& &&变为some_type&。因此std::forward会返回左值引用。

因此,对原始问题的最终答案是std::forward的返回类型仅取决于作为std::forward模板参数传递的类型。由于您的案例中的T将始终推断为非引用类型,因此std::forward将始终返回rvalue-reference。