【问题标题】:A function template using std::forward and rvalue使用 std::forward 和 rvalue 的函数模板
【发布时间】:2013-08-24 17:48:03
【问题描述】:

给定以下来自“C++ 编程语言第 4 版”的函数模板:

template <typename TT, typename A>
unique_ptr<TT> make_unique(int i, A && a)
{
      return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};
} 

我发现很难理解它的实际作用,

a 绝对是一个右值,因此 make_unique 函数 似乎在堆上分配其内容并将该地址保存在 unique_ptr 中,因此我们不必担心删除它。但是,标准库的转发功能是做什么的? (我想这与存在右值有关)我尝试阅读 C++ 文档,但我似乎没有正确理解这一点。 很想从更有经验的 C++ 程序员那里得到一个很好的解释。

谢谢!

【问题讨论】:

    标签: c++


    【解决方案1】:

    嗯...我很确定这不是作为未来std::make_unique 的变通实现,但无论如何,该函数的作用很容易理解,尽管它需要您事先了解 C++11 的新特性。

    template <typename TT, typename A>
    unique_ptr<TT> make_unique(int i, A && a)
    {
          return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};
    }
    

    首先make_unique是一个函数模板,我真的希望你已经知道了,因为下面会要求你至少有最基本的知识关于模板的作用以及模板的工作原理。

    现在到重要的部分。 A &amp;&amp; a 有一个函数参数。具体来说,a 是函数参数,其类型为A&amp;&amp;,即r-value reference。由于它的类型是模板类型参数,我们可以从调用者作为参数传递给a 的任何内容推断出它的类型。每当我们有 r 值引用和参数类型推导、特殊推导规则和引用折叠启动时,我们就有一个所谓的“通用引用”,这对于完美的转发功能特别有用。 p>

    只要我们有一个通用引用(在我们的例子中是a),我们几乎总是希望在我们想要使用它们时保留其原始的“左值”或“右值”。为了有这种行为,我们几乎应该总是使用std::forward (std::forward&lt;A&gt;(a))。通过使用std::forward,最初作为左值传递的变量仍然是左值,而最初作为右值传递的变量仍然是右值。

    之后,事情就简单了

    return unique_ptr<TT>{new TT{ i, std::forward<A>(a) }};
    

    注意大括号的使用。它不使用括号,而是使用 C++11 的 uniform initialization 调用构造函数的语法。使用new TT{ i, std::forward&lt;A&gt;(a) },您可以动态分配TT 类型的对象,并在大括号内使用给定的参数。使用unique_ptr&lt;TT&gt;{new TT{ i, std::forward&lt;A&gt;(a) }};,您正在创建一个unique_ptr&lt;TT&gt;,其参数是动态分配返回的参数。然后从函数返回 unique_ptr&lt;TT&gt; 对象。

    【讨论】:

      【解决方案2】:

      由于模板参数推导和引用折叠规则,您无法知道a 是右值引用还是左值引用。 std::forward 将参数传递给 TT 委托人,就像它传递给 make_unique 一样。 Scott Meyers 将 A&amp;&amp; 称为 universal reference,因为它可以是左值引用或右值引用,具体取决于传递给 make_unique 的内容。

      如果您将右值Foo 传递给make_uniquestd::forward 将传递一个右值引用。

      如果将左值 Foo 传递给 make_uniquestd::forward 将传递左值引用。

       make_unique(1, Foo());         // make_unique(int, A&&) -> rvalue ref
       Foo f;
       make_unique(1, f);             // make_unique(int, A&&&) -> make_unique(int, A&) -> lvalue ref
       make_unique(1, std::move(f));  // make_unique(int, A&&&&) -> make_unique(int, A&&) -> rvalue ref
      

      【讨论】:

        猜你喜欢
        • 2014-04-15
        • 1970-01-01
        • 2016-08-22
        • 2022-01-05
        • 1970-01-01
        • 2015-11-30
        • 2017-01-31
        • 2021-10-10
        • 2017-02-23
        相关资源
        最近更新 更多