std::forward的可能实现

huangapple go评论71阅读模式
英文:

std::forward's possible implementation

问题

以下是翻译好的内容:

  1. 为什么在第一种情况下编写std::forward(x)是可行的,但在第二种情况下不可行?也就是说,为什么在第二种情况下类型推断不起作用?
  2. 编写std::forward(x)有什么问题?我明白它与标准的std::forward<T>(x)签名不匹配,但随之而来的另一个问题是:为什么我们需要在这里明确指定类型?
英文:

I am curious why the below implementation is wrong?

template&lt;typename T&gt;                // For lvalues (T is T&amp;),
T&amp;&amp; std::forward(T&amp;&amp; param)         // take/return lvalue refs.
{                                   // For rvalues (T is T),
    return static_cast&lt;T&amp;&amp;&gt;(param); // take/return rvalue refs.
}

According to "Effective Modern C++" book, this is the possible implementation of std::forward which is understandable.

template&lt;typename T&gt;
T&amp;&amp; forward(remove_reference_t&lt;T&gt;&amp; param)
{
    return static_cast&lt;T&amp;&amp;&gt;(param);
}

A user in the comments here answered like this:

> In the first case, you could get away with std::forward(x), but in the
> second you must explicitly provide the template parameters, as they
> cannot be inferred.

Questions

  1. Why in the 1st case writing std::forward(x) is possible, but for
    the 2nd case it is not? I.e., why in the 2nd case type deduction
    won't work?
  2. What is wrong with writing std::forward(x)? I understand that it doesn't match with
    the standard's std::forward&lt;T&gt;(x) signature, but then another questions comes: why we need to specify type explicitly here?

答案1

得分: 3

(1) 是一个身份函数,它原样返回参数,这使它无用。

(2) 仅接受左值,并根据 T 返回左值或右值。请注意,std::forward 还有一个第二个重载,接受右值并返回右值,但它大多数情况下无用。

即,为什么在第二种情况下类型推断不起作用?

因为推断无法通过 typedefs (remove_reference_t) 传播。而且,当原始值可以是 TT &T && 时,你怎么能取消 remove_reference 呢?

使用 std::forward(x) 有什么问题?

转发的整个目的是接受一个左值,并有条件地将其转换为右值或保持为左值。这需要外部信息来决定是否进行转换,在这种情况下,信息来自于 T

理论上,你可以获得你想要的语法(不需要模板参数),但这需要一个宏,例如只是 #define FWD(...) decltype(__VA_ARGS__)(__VA_ARGS__)

在这种情况下,额外的信息来自于 decltype(x),它具有检测变量的右值引用特性的神奇能力,即使变量名称本身始终是左值。

英文:

(1) is an identity function, it returns the argument as is, which makes it useless.

(2) only accepts lvalues, and returns either an lvalue or an rvalue depending on T. Note that std::forward also has a second overload that accepts an rvalue and returns an rvalue, but it's mostly useless.

> I.e., why in the 2nd case type deduction won't work?

Because deduction can't propagate through typedefs (remove_reference_t). And indeed, how could you unremove_reference, when the original could've been T, T &amp;, or T &amp;&amp;.

> What is wrong with writing std::forward(x)?

The whole point of forwarding is to take an lvalue, and to conditionally either cast it to an rvalue or keep as an lvalue. This requires external information to decide whether to cast, and in this case it comes from T.

In theory it's possible to get the syntax you want (without the template argument), but this requires a macro, e.g. just #define FWD(...) decltype(__VA_ARGS__)(__VA_ARGS__).

In this case the extra information comes from decltype(x), which has the magical ability to detect the rvalue-reference-ness of the variable, even though the variable name by itself is always an lvalue.

huangapple
  • 本文由 发表于 2023年7月28日 01:52:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/76782317.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定