zoukankan      html  css  js  c++  java
  • 翻译「C++ Rvalue References Explained」C++右值引用详解 Part7:Perfect Forwarding(完美转发):问题

    本文为第七部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.html

    Perfect Forwarding(完美转发):问题

    Move语义背后右值引用用来解决的另一个问题是完美转发问题。考虑下面这样简单的工厂函数:

    template<typename T, typename Arg> 
    shared_ptr<T> factory(Arg arg)
    { 
      return shared_ptr<T>(new T(arg));
    }

    显然,这里的目的是想要将arg参数通过工厂函数传递到T的构造函数中去。理想情况,就arg而言,一切应该表现得如同没有工厂函数一样,构造器直接被客户的代码调用:也就是完美转发。上面的代码很不幸在这种状况下失败了:它引入了一个额外的传值调用,当构造器使用引用类型作为参数时,那么这样就是很糟糕的了。

    一个更为普遍的解决方案,例如被boost::bind所采用的,就是让外层的函数的参数使用引用类型:

    template<typename T, typename Arg> 
    shared_ptr<T> factory(Arg& arg)
    { 
      return shared_ptr<T>(new T(arg));
    }

    这样更好,但也并非完美。问题就是现在的工厂函数并不能被右值所调用:

    factory<X>(hoo()); // error:如果hoo通过值返回
    factory<X>(41); // error

    这可以通过提供一个const reference的参数重载来解决:

    template<typename T, typename Arg> 
    shared_ptr<T> factory(Arg const & arg)
    { 
      return shared_ptr<T>(new T(arg));
    }

    这个方法有两个问题。首先,如果factor不仅仅只有一个,而是有很多个参数的话,你就需要提供所有对non-const和const reference参数的组合重载。因此,这种解决方案当面临到函数有很多参数的时候可伸缩性是很差的。

    第二个,这种方法并不是完美的是因为它会阻挡move语义:在factory函数体中的T构造器重的参数是一个左值。因此,move语义永远不会发生即使没有外在的包装函数。

    事实证明右值引用可以用来解决这类问题。它使得可以不用通过任何的重载就可以实现真正的完美转发。为了理解它是如果运作的,我们需要先看一下右值引用的两个规则。

  • 相关阅读:
    WinRAR5.01注册码附注册机
    PS不能存储,因为程序错误
    mysql中 date datetime time timestamp 的区别
    sublime text 3 3126 注册码+中文包
    IIS7.5 用 IIS AppPool应用程序池名 做账号 将各站点权限分开
    linux vi 报错 E37: No write since last change (add ! to override)
    Linux 安装 apache2.4.23
    三级分类及名称及列表
    二级栏目名称及列表
    每隔N行输出不同样式
  • 原文地址:https://www.cnblogs.com/harrywong/p/perfect-forwarding-the-problem.html
Copyright © 2011-2022 走看看