【问题标题】:Using std::forward with a non-forwarding, plain old reference将 std::forward 与非转发的普通旧引用一起使用
【发布时间】:2018-05-30 04:15:12
【问题描述】:

找朋友:

为什么下面代码中的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 在此处不是通用/转发引用。我知道这个功能如果真的有用的话很可能会更有用,但还是很好奇。

【问题讨论】:

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


【解决方案1】:

要了解这种情况,您必须了解转发引用的工作原理。给定一个类似的定义

template <typename T>
void foo(T&& t) {}

当你写类似的东西时

some_type some_object;
foo(some_object);

模板推演推导出Tsome_type&amp;。现在参数t 的类型为some_type&amp; &amp;&amp;。由于您不能引用引用,因此将应用 reference collapsing 规则并将 some_type&amp; &amp;&amp; 折叠为 some_type&amp;

如果你写了类似的东西

some_type some_object;
foo(std::move(some_object));

模板推演推导出Tsome_type。现在参数t 的类型为some_type&amp;&amp;。这是一个完全有效的类型,所以不会发生引用折叠。

现在我们到达std::forward。所有std::forward&lt;U&gt; 所做的只是将其参数转换为U&amp;&amp;。如果Usome_type,如上面的第二种情况,则将参数强制转换为some_type&amp;&amp;。它仍然是一个右值引用。如果Usome_type&amp;,和上面的第一种情况一样,引用折叠再次执行,some_type&amp; &amp;&amp; 变为some_type&amp;。所以std::forward 返回一个左值引用。

所以你原来的问题的最终答案是std::forward 的返回类型只取决于作为std::forward 的模板参数传递的类型。由于在您的情况下 T 将始终被推断为非引用类型,因此 std::forward 将始终返回右值引用。

【讨论】:

  • 接受了最详细的答案。
【解决方案2】:

std::forward&lt;T&gt;(c) 等价于static_cast&lt;T&amp;&amp;&gt;(c)

如果T&amp;&amp; 是转发引用,那么这允许将左值作为左值转发,因为T 将被推断为左值引用类型,而T&amp;&amp; 将通过引用折叠成为相同的左值引用类型规则。在您的情况下,T&amp;&amp; 不是转发引用,因此这不起作用。

【讨论】:

    【解决方案3】:

    好吧,std::forward&lt;T&gt;(x) 的定义是将x 转换为类型T&amp;&amp;。如果你传递一个非引用作为参数,你会得到一个右值引用T&amp;&amp;。由于您的T 不能是引用类型(您不能有对引用的引用),所以它必须是非引用类型。

    【讨论】:

      猜你喜欢
      • 2018-07-30
      • 2020-10-23
      • 2021-08-29
      • 1970-01-01
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      • 2013-06-30
      • 1970-01-01
      相关资源
      最近更新 更多