【问题标题】:std::forward acting differentlystd::forward 行为不同
【发布时间】:2021-05-20 01:28:12
【问题描述】:

我目前正在学习 C++ 中的完美转发,但遇到了一些让我感到困惑的事情。很确定这是一件愚蠢的事情。当我在左值上使用 std::forward 时,它使用了右值函数。这是一个非常糟糕的解释,所以我只显示代码。

#include <iostream>

void check(int&& other) {
    std::cout << "Rvalue" << std::endl;
}

void check(int& other) {
    std::cout << "Lvalue" << std::endl;
}

void call(int& other) {
    check(std::forward<int>(other));
}

int main()
{
    int i = 4;
    call(i);
}

这会输出“右值”。请帮助我理解原因。

【问题讨论】:

  • 使用std::forward唯一原因在于接受通用模板引用template&lt;T&gt; void func(T&amp;&amp; other)的方法。话虽如此,这个问题写得很好,值得回答。
  • 这能回答你的问题吗? What's the difference between std::move and std::forward There's an answer of mine there 我对 std::forwardstd::move 做了相同的解释步骤,我认为这对两者都有很多见解。

标签: c++ perfect-forwarding


【解决方案1】:

模板中使用“完美转发”,即:

template<typename T>
void func(T && arg)
{
    func2(std::forward<T>(arg));
}

在模板上下文之外,最终结果会发生巨大变化。 std::forward 所做的只是return static_cast&lt;T &amp;&amp;&gt;,所以你的call 函数只不过是:

void call(int& other) {
    check(static_cast<int &&>(other));
}

因此你得到一个右值。这在模板中的工作方式不同的原因是因为&amp;&amp; 模板参数是一个转发引用(对于左值或右值推导引用的一个花哨术语,取决于该参数中删除了什么),并且由于reference collapsing rules。简而言之,当在模板上下文中使用时,最终结果是:

  1. T 被推断为左值或右值引用,具体取决于参数是什么。

  2. 如果T 是左值引用,则static_cast&lt;T &amp;&amp;&gt; 的结果是左值引用,如果T 是右值引用,则结果是右值引用,因为引用折叠规则。

最终结果是转发相同类型的引用。但这仅适用于模板上下文,因为它需要转发引用语义和引用折叠规则才能工作恰到好处

【讨论】:

    【解决方案2】:

    std::forward() 并不完全是魔法。这是必须为其提供具有适当参考类别(右值参考、左值参考、无参考)的适当类型的原因之一。

    通常,您从模板参数中获取类型。如果它是auto&amp;&amp;-argument(C++14 lambda、C++20 缩写模板或概念的使用),则使用 decltype() 从函数参数中获取它。

    手动指定它有效,但与使用该功能的精神背道而驰。 std::move() 或参数本身在这种情况下更容易使用,具体取决于您指定的模板参数。

    由于引用折叠和std::forward() 的定义方式,TypeType&amp;&amp; 都产生右值引用,而Type&amp; 产生左值引用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-08
      • 1970-01-01
      • 1970-01-01
      • 2014-10-15
      • 2014-06-12
      • 2016-11-27
      • 1970-01-01
      • 2015-05-03
      相关资源
      最近更新 更多