C模板19(Function类模板的实现)
看来可能还真是文章的篇幅问题,我拆分后提交很快就审核通过了。
好了,回到正题。我们继续实现Function类模板。 Function() noexcept : holder_(nullptr) {} Function(Function const &rhs) : holder_(rhs.holder_ == nullptr ? nullptr : rhs.holder_->clone()) {} Function(Function &rhs) noexcept : Function(static_cast(rhs)) {} Function(Function &&rhs) noexcept : holder_(rhs.holder_) { rhs.holder_ = nullptr; } template Function(Callable &&c) : holder_(nullptr) { using Functor = std::decay_t; using Holder = FunctionStorage; holder_ = new Holder(std::forward(c)); } ~Function() { delete holder_; }
我们看看它的构造函数的定义,都非常容易理解,使用构造参数合理地完成holder_的初始化:1. 缺省构造函数直接将内部对象指针设为null,这时没有实际的可调用对象;2. 拷贝构造函数利用虚拟拷贝接口完成复制;3. 移动构造函数就更加直接了,只是简单的一个指针的赋值,不过别忘记了将源对象的内部指针设为null,否则那个对象析构了,这里的holder就成悬挂指针了;4. 最后的模板构造函数稍微复杂一些,注意要将Callable的推导类型decay,防止引用类型的推导结果。最后一点,由于对象内部存储的是指针,别忘了在析构函数里释放内存。 Function &operator=(Function const &rhs) { Function tmp(rhs); swap(*this, tmp); return *this; } Function &operator=(Function &rhs) { this->operator=(static_cast(rhs)); return *this; } Function &operator=(Function &&rhs) noexcept { delete holder_; holder_ = rhs.holder_; rhs.holder_ = nullptr; return *this; } template Function &operator=(Callable &&c) { Function tmp(std::forward(c)); swap(*this, tmp); return *this; }
Function的赋值操作符的定义是实现"类型擦除"的关键,因为赋值对象的内部可调用对象可能与被赋值对象的当前内部对象类型不一样,不过这个差异被FunctionBase指针屏蔽了,这样拥有共同接口的类型在这里就当成是"同一类型"了,至少它们之间可以相互赋值。 explicit operator bool() const { return holder_ != nullptr; } R operator()(Args... args) const { return holder_->call(args...); }
最后是Function的主要接口operator(),同时提供一个bool()转换运算符是方便用户检测它是否正确初始化了(是否可被调用)。好了,简化版本的std::function实现完毕。下面我们写一些测试代码来检验一下代码是否正确。 Function f; // default ctor assert(!f);
我们先测试一下Function的缺省构造函数,顺便测试一下咱们定义的bool转换符。double foo(int i, std::string s) { std::cout << "double foo(int, string) "; return 0.99; } Function f2 = foo; // ctor(T&&) f2(3, "hello");
接着我们看一下用一个函数指针来构造Function对象,这个会调用最后定义的那个模板构造函数,然后测试一下Function对象的可调用性。class X { public: double operator()(int i, string s) const { cout << "double X::operator(int, string) "; return 32.3; } }; f = X(); // operator=(T&&) assert(f);
这里我们把一个X对象赋值给f,测试Function的移动语义赋值操作符,这个时候f对象就具备可调用性了。
其它的测试代码就不一一列出了,有兴趣的朋友请下载完整代码:
代码在functional目录
辽篮老将们还能撑多久?卫冕赛季的三连胜喜中有忧上个赛季辽浙总决赛G4,在确定冠军到手的情况下,比赛最后一分钟,杨鸣颇有仪式感地派上了郭艾伦,韩德君,李晓旭赵继伟和刘志轩五位老将。他们在辽篮都效力超过了10个赛季以上,并且都参与
澳门城市大学联合多方举办万山岛渔旅融合策划创意邀请赛由珠海市万山镇政府香洲区万山村会国际旅游与区域发展学会策划指导,珠海市农控海洋产业发展有限公司及澳门城市大学国际旅游与管理学院主办的渔旅融合万山岛旅游发展调研策划创意邀请赛决赛日前
红米将发布其首款游戏电视红米XPro小米推出了一系列新产品,包括Redmi品牌的游戏电视。它被称为红米XPro游戏电视,并将很快在中国首次亮相。它将于10月31日在中国发布。我们也预计RedmiNote12系列也将在
制造业如何在数字变革中蓬勃发展并引领革命当前世界面临着第四次工业革命,气候约束不断增大,国际紧张局势加剧,经济不确定性增加,制造业企业必须开发新的能力以适应外界的变化。一些企业采用先进制造技术和解决方案在变局中脱颖而出,
美联储还要加息,强势的美元导致了全球什么问题?随着美联储疯狂加息,经济影响传导到了大多数国家,特别是发展中国家和依靠进口的国家,更是过的不好。在开罗,生活成本飙升,很多人不得不将妻子和年幼的孩子送到大城市以外的村庄与父母一起生
勐海茶厂茶源朝圣之旅火爆勐海茶厂茶人心中的圣地拥有82年历史的勐海茶厂是现代普洱茶产业的梦工厂,这里拥有占地700多亩的普洱茶综合加工区,拥有巴达山布朗山两个万亩茶园基地这里是现代普洱茶人工后发酵技术的诞
江苏昆山市巴城镇阳澄湖岸边的蟹镇巴城风光日前,小区偶遇停水停电,遂决定去昆山市内一游。乘车城中观光,座前一妇人,自称巴城人,自上海回家。问其巴城有何可游之处?答曰,巴城有蟹,有老街。昆山市巴城镇早有所闻,为昆山西
Robotaxi商业化合纵连横,车企掘金文智能相对论作者陈明涛当下,有多方力量已经盯上Robotaxi这块巨大的蛋糕。只是Robotaxi商业化并非一蹴而就,需要大家形成资源互补产业协同,打造从技术研发到落地持续运营的商
93年前在一个小山村,毛主席和3位元帅1位大将差点全军覆没1927年到1928年是中国红军发展的重要时期,井冈山根据地在毛主席的带领下初步形成,这期间国民党多次企图破坏根据地的建设,毛主席等人数次化险为夷,最终成功粉碎敌人的图谋。围魏救赵
彩虹岛儿时回忆,彩虹岛手游回归!快来找寻属于你的那份回忆吧彩虹岛是由韩国游戏公司开发,2007年2月盛大代理的一款休闲冒险游戏。清新可爱的画风加上人物卡通的造型,让他在2008年就被中国大陆文化部评为最适合未成年人的网络游戏。当时有不少年
五路都会,亚瑟全能更甚者,辅助为核2022电竞季XYG今年夏季赛季后赛一轮游的爆冷,真的让很多人都没有想到。正如网友那句一胎养废了,那就生个二胎吧!,逆子们比赛的草草收场,水手相信很多老粉这段时间都感觉少了点什么。