【问题标题】:C++ std::forward<T> vs static_cast<T>C++ std::forward<T> 与 static_cast<T>
【发布时间】:2015-09-27 09:42:27
【问题描述】:

据我了解,std::forward&lt;T&gt;(x) 等同于static_cast&lt;T&amp;&amp;&gt;(x)

但据我所见,static_cast&lt;T&gt;(x) 似乎做了同样的事情,如下图code 所示

因此,我的问题是为什么 std::forward&lt;T&gt; 实现为 static_cast&lt;T&amp;&amp;&gt;(x),而不是 static_cast&lt;T&gt;(x),如果两者具有相同的效果?

【问题讨论】:

  • 你没有尝试使用int&amp;
  • @Quentin 在这种情况下,它总是返回一个左值。
  • static_cast&lt;T&gt; 会创建一个右值的副本
  • 因为你想转发引用而不是值
  • 尝试使用一个类,您将在其中检测副本并移动 ctor 以产生输出,并观察差异。

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


【解决方案1】:

因为完美转发允许传递右值引用左值引用。这是通过reference collapsing 完成的:

T = int    --> T&& = int&&
T = int&   --> T&& = int& && = int&
T = int&&  --> T&& = int&& && = int&&

在您使用static_cast&lt;T&gt; 的示例中,您只是丢失了右值引用。它适用于原始类型(因为传递 int 通常是复制 CPU 寄存器值),但对于复杂类型来说很糟糕,因为它会导致通过复制 ctor 创建临时对象。

【讨论】:

  • 我刚查了一下,它实际上是调用右值的复制构造函数。但为什么?我读到如果我们用右值调用 func(),T 被推导出为 int&&,所以 static_cast(x) 将变为 static_cast(x)。那么为什么它会创建一个副本呢?
  • static_cast&lt;T&gt; 可以返回参考:上面的答案暗示它不能。你能澄清一下这个问题只发生在一个“案例”中吗?
  • @Mikrosaft: 不,T 不能推导出为int&amp;&amp;,只能是intint&amp;
  • @myaut 现在很有意义。谢谢!
【解决方案2】:

如果T&amp;&amp; 是一个右值引用,那么T 是一个值,那么static_cast&lt;T&gt; 使一个复制 不是一个右值引用。

该副本将绑定到右值引用(就像引用一样),但可能会不必要地调用复制/移动 ctor,并且它不是省略的候选对象。

static_cast&lt;T&amp;&amp;&gt; 同时将转换为右值引用。

它们在其他方面是相同的。

【讨论】:

    【解决方案3】:

    我同意 Yakk,但比这更糟。

    void foo(const std::vector<int> &vec);
    
    template<typename T>
    void callFoo(T &&data)
    {
        foo(static_cast<T>(data));
    }
    
    int main()
    {
        callFoo(std::vector<int>{/*...*/});
    }
    

    这将始终创建一个副本。向量没有移动,因为data 作为一个表达式,是std::vector&lt;int&gt; 类型的左值,即使替换的类型是std::vector&lt;int&gt;&amp;&amp;。请注意,Tstd::vector&lt;int&gt;,而不是 std::vector&lt;int&gt; &amp;&amp;。故事的寓意:使用标准库,它做正确的事,forward 这个名字也比static_cast&lt;something&gt; 更能抓住意图。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-10
    • 2019-04-14
    • 2014-06-12
    • 2023-03-28
    • 2019-01-10
    • 2016-03-21
    • 1970-01-01
    • 2016-01-23
    相关资源
    最近更新 更多