为什么std :: forward将左值和右值转换为右值引用?

时间:2017-05-14 08:25:28

标签: c++ c++11 lvalue rvalue

我想我对std::forward感到困惑。 我使用std::forward的函数如下,但它被简化和修改以便于解释。

// This is an example code to explain my question simply.
template <typename Element>
void add(Element&& element) {
    static std::vector vec;
    vec.push_back(std::forward<Element>(element));
}

我用上面的函数试了两个案例;案例1左值论证和案例2右值论证。

案例1:左值论证

auto some_class = SomeClass();
add(some_class);

案例2:右值论证

add(SomeClass());

在调试器中,两种情况都传递相同的以下部分,std::forward部分和std::vector部分。

std::forward部分:

template<typename _Tp>
constexpr _Tp&&
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
{ return static_cast<_Tp&&>(__t); }

std::vector部分:

#if __cplusplus >= 201103L
  void
  push_back(value_type&& __x)
  { emplace_back(std::move(__x)); }

似乎std::forward部分将两个案例转换为右值引用&&,因为它使用static_cast<_Tp&&>。并且std::vector将这两个元素视为右值引用,因为它使用std::move()

我预计案例1的增加是左值,因为它有自己的名称,案例2是右值,因为它没有自己的名字。 我也期望std::forward将案例1转换为左值引用,将案例2转换为右值引用。  我对左值,右值和std::forward的理解是否正确?如果是这样,为什么std::forward会将两者都转换为右值引用&&

如果我犯了错误,我很抱歉花时间。

2 个答案:

答案 0 :(得分:2)

  

为什么std::forward将两者都转换为右值参考

不应该。根据{{​​3}}的规则,当左值传递给add时,模板类型参数Element将推导为SomeClass&。然后将调用std::forward<SomeClass&>(element)std::forward的实例化将是

// before reference collapsing
constexpr SomeClass& &&
forward(SomeClass& __t) noexcept
{ return static_cast<SomeClass& &&>(__t); }

// after reference collapsing
constexpr SomeClass&
forward(SomeClass& __t) noexcept
{ return static_cast<SomeClass&>(__t); }

因此,对于第一种情况,std::forward将返回左值。从函数返回的左值引用是左值。

BTW,对于第二种情况,templare参数Element将推导为SomeClass,然后您可以进行与上述相同的推断,最后std::forward的实例化将是

constexpr SomeClass&&
forward(SomeClass& __t) noexcept
{ return static_cast<SomeClass&&>(__t); }

从函数返回的rvalue-reference是一个rvalue。

你得到的结果似乎很奇怪,对于第一种情况,应该调用std::vector::push_back(const T&)。 (我尝试了forwarding referencemcve

答案 1 :(得分:1)

您缺少的部分是参考折叠。在传入左值时,对于某些T&,它将具有const T&(或T)类型。如果您将其添加到forward模板中,则会获得:

return static_cast<T& &&>(__t);

由于参考折叠规则,这会折叠为T&

有效的现代C ++在第28项中涵盖了这一点。基本上:

  • 类型T的左值推导为T&
  • 类型T的Rvalues推导为T

有了这个,以及上面的参考折叠规则,希望你能理解std::forward的工作原理。