为什么std :: forward有两个重载? [英] Why does std::forward have two overloads?

查看:156
本文介绍了为什么std :: forward有两个重载?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下参考折叠规则


  • T& & -> T&

  • T&& & -> T&

  • T& && -> T&

  • T& && -> T&&

  • T& & --> T&
  • T&& & --> T&
  • T& && --> T&
  • T&& && --> T&&

第三和第四条规则暗示 T(ref qualifer)& 是身份转换,即 T& 停留在 T& T& 停留在 T&& ; 。为什么 std :: forward 有两个重载?以下定义不能满足所有目的吗?

The third and fourth rule imply that T(ref qualifer) && is the identity transformation, i.e. T& stays at T& and T&& stays at T&&. Why do we have two overloads for std::forward? Couldn't the following definition serve all purposes?

template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& forward(const typename std::remove_reference<T>::type& val) {
    return static_cast<T&&>(const_cast<T&&>(val));
}

这是 const std :: remove_reference<的唯一目的; T& 的用途是不进行复制。 enable_if 有助于确保仅在非const值上调用该函数。我不确定是否需要 const_cast ,因为不是引用本身就是常量。

Here the only purpose the const std::remove_reference<T>& serves is to not make copies. And the enable_if helps ensure that the function is only called on non const values. I'm not entirely sure whether the const_cast is needed since it's not the reference itself that's const.

forward 总是使用显式模板参数调用,我们需要考虑两种情况:

Since forward is always called with explicit template parameters there are two cases we need to consider:


  1. forward< Type&>(val)这是 forward <中的 T 的类型/ code>将是 T& ,因此返回类型将是将身份转换为 T&

  2. forward< Type&&>(val)这里的 T 转发中的c>将为 T& ,因此返回类型将是标识转换为 T&&

  1. forward<Type&>(val) Here the type of T in forward will be T& and therefore the return type will be the identity transformation to T&
  2. forward<Type&&>(val) Here the type of T in forward will be T&& and therefore the return type will be the identity transformation to T&&

那么为什么我们需要两个重载,如 http://en.cppreference.com/w/cpp/utility/forward

So then why do we need two overloads as described in http://en.cppreference.com/w/cpp/utility/forward?

注意:我我不确定 std :: forward 是否曾经与 const 类型一起使用,但是我禁用了在这种情况下前进,因为我从未见过这样使用过。同样,在这种情况下,移动语义也没有任何意义。

Note: I am not sure if std::forward is ever used with const types, but I disabled forward in that case, because I have never seen it used like that. Also move semantics don't really make sense in that case either.

推荐答案

一个好的起点是霍华德·辛南特(Howard Hinnant)的< href = https://stackoverflow.com/a/29135875/2069064> answer 和纸张放在 std :: forward()上。

A good place to start would be Howard Hinnant's answer and paper on std::forward().

您的实现可以正确处理所有 normal 用例( T&-> T& T const&-$ T const& T&&-> T&& )。它无法处理的是常见且易于制造的错误,这些错误在实现中很难调试,但无法使用 std :: forward()进行编译。

Your implementation handles all the normal use-cases correctly (T& --> T&, T const& --> T const&, and T&& --> T&&). What it fails to handle are common and easy-to-make errors, errors which would be very difficult to debug in your implementation but fail to compile with std::forward().

给出以下定义:

struct Object { };

template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& my_forward(const typename std::remove_reference<T>::type& val) {
    return static_cast<T&&>(const_cast<T&&>(val));
}

template <class T>
void foo(T&& ) { }

我可以通过非 const const 对象的引用,都是左值变量:

I can pass non-const references to const objects, both of the lvalue variety:

const Object o{};
foo(my_forward<Object&>(o));    // ok?? calls foo<Object&>
foo(std::forward<Object&>(o));  // error

和右值变化:

const Object o{};
foo(my_forward<Object>(o));    // ok?? calls foo<Object>
foo(std::forward<Object>(o));  // error

我可以将左值引用传递给右值:

I can pass lvalue references to rvalues:

foo(my_forward<Object&>(Object{}));   // ok?? calls foo<Object&>
foo(std::forward<Object&>(Object{})); // error

前两种情况可能导致潜在地修改原本为<$ c $的对象c> const (如果它们是 const 的话,可能是UB),最后一种情况是传递一个悬挂的左值引用。

The first two cases lead to potentially modifying objects that were intended to be const (which could be UB if they were constructed const), the last case is passing a dangling lvalue reference.

这篇关于为什么std :: forward有两个重载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆