代码之家  ›  专栏  ›  技术社区  ›  Leonid Volnitsky

什么时候不使用带有r值的std::forward?

  •  7
  • Leonid Volnitsky  · 技术社区  · 12 年前

    什么情况下 std::forward 不需要吗?它用于包装被模板化为右值的内部函数参数(也就是说,它可以是左值或命名为右值)。喜欢在:

    template<class T>
    void outer(T&& t) { 
        inner(std::forward<T>(t)); 
    }
    

    我猜有一种情况是内部函数参数通过值传递。还有其他情况吗?我在写作的时候有个问题 std::begin(std::forward<Ct>(ct)) 其中Ct是模板-右值-ref。

    编辑 关于可能的重复

    如果我没记错的话,这是一些不理解这个问题的新手第三次尝试将这个4年前的问题作为重复来结束。

    “使用forward的优点?”和“何时不使用带有r-值的std::forward?”是非常不同的问题。首先介绍了初学者的r值,其次讨论了高级C++用户的完美转发。我是的作者 meta-template library 和lambda库,它们不需要详细的基础描述。答案中的信息和其他问题大不相同。

    3 回复  |  直到 8 年前
        1
  •  6
  •   Community Neeleshkumar S    7 年前

    当模板参数类型包含值类别时,可以实现完美转发。(如果这句话没意思,花点时间 familiarize yourself with the problem at hand .)

    给定:

    template <typename T>
    void foo(T&& x); 
    

    体内 foo , T 要么采取 U U& 。前者表示我们被传递了一个右值,后者表示我们被传了一个左值。我们可以 向前地 这个事实是这样的:

    template <typename T>
    void foo(T&& x)
    {
        bar(std::forward<T>(x));
    }
    

    将左值传递给 , bar 得到相同的左值。将右值传递给 , 酒吧 得到右值。

    如果您不能区分一个值类别,那么转发就没有用了。只有当您有一个以与上面相同的方式推导的模板参数时,它才有用。所以,是的,它在这里没有用:

    template <typename T>
    void foo(const T& x)
    {
        // if this was called as foo(1), we're none the wiser
    }
    
        2
  •  3
  •   Leonid Volnitsky    8 年前

    我正在回答我自己的问题,因为到目前为止我还没有得到满意的答案。 如果我能得到哪怕是一点小小的改进/补充,我会选择你的答案作为接受。

    一般来说 std::forward 如果 完美转发 将实现。否则就是多余的。

    使用 std::正向 仅当以下任何一项为真时,才能包装内部函数arg:

    • 内部函数参数是模板化的rvalue-ref(现在称为“转发引用”);
    • 内部函数具有多个重载,这些重载基于参数r/l值进行区分;
    • 内部函数具有多个重载,这些重载基于常量来区分左值参数;
        3
  •  -1
  •   WaltK    8 年前

    使用std::forward(对模板化函数的形式参数,其类型为T&&,T是模板的类型参数):

    • 当内部函数调用是外部函数中参数的最后一次使用时,以及
    • 在可能的情况下,内部函数的重载可能会也可能不会将参数作为右值引用。

    其原理是,当一个对象可能被右值引用作为参数传递时(这是您使用std::forward所允许的),它的信息内容可能会被破坏。所以,只有当你确信自己不再使用这些信息内容时,你才想这样做。

    示例:

    #include <utility>
    
    template <class T> void f(T &&t);
    template <class T> void g(const T &t);
    
    template <class T>
    void outer(bool f_first, T &&t)
      {
        if (f_first)
          {
            f(t);
            g(t);
          }
        else
          {
            g(t);
            f(std::forward<T>(t));
          }
      }
    
    #include <string>
    
    void foo(std::string s)
      {
        outer(true, s);
        outer(true, s + "x");
        outer(false, s);
        outer(false, std::move(s));
      }