范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

C辨析函数指针函数对象Lambda表达式及后者最优的原因

  试想有一排序函数sort(int arr[])默认为升序排序,如果想更改为降序排列,最直接的方法就是在函数体中修改比较运算符,但这种修改函数体的方法不够灵活,特别是如果sort(int arr[])要封装到库(接口与实现分离)时,库使用者是无法去修改函数体的。理想的方法是修改接口,在接口在添加一函数指针做为形式参数,在函数体中调用函数指针,这样,函数体中的代码就可以固定下来,而选择升序还是降序排列,则由函数指针指向的函数来决定。
  函数指针、函数对象、Lambda表达式都可以实现同样的功能:#include  #include  using namespace std;  struct FuncObj {     constexpr FuncObj() = default;     int operator()(int a) {         return run(a);     }     // this is a non-capturing lambda, the operator can be     // in a static function     static int run(int a) {         return a;     } };  typedef int (*funcp)(int a); //template  //int func(int a) int func(int a, funcp foo) {     foo(a); } int func(int a,FuncObj lt) {     lt(a); }  int funcpRelated(int a) {     return a; }  int main()  {     auto lambda = [](int a) { return a; };     funcp ptr = lambda;  // 类型相同,不能捕捉     cout< f_int_obj = FuncObj();     cout<(1); // ---> this is working     return 0; }
  函数指针、函数对象、Lambda表达式对STL算法的使用:#include  #include  #include  #include  #include  const long Size1 = 39L; const long Size2 = 100*Size1; const long Size3 = 100*Size2;  bool f3(int x) {return x % 3 == 0;} bool f13(int x) {return x % 13 == 0;}  int main() {     using std::cout;     std::vector numbers(Size1);      std::srand(std::time(0));     std::generate(numbers.begin(), numbers.end(), std::rand);  // using function pointers     cout << "Sample size = " << Size1 << " ";      int count3 = std::count_if(numbers.begin(), numbers.end(), f3);     cout << "Count of numbers pisible by 3: " << count3 << " ";     int count13 = std::count_if(numbers.begin(), numbers.end(), f13);     cout << "Count of numbers pisible by 13: " << count13 << "  ";  // increase number of numbers     numbers.resize(Size2);     std::generate(numbers.begin(), numbers.end(), std::rand);     cout << "Sample size = " << Size2 << " "; // using a functor     class f_mod     {     private:         int dv;     public:         f_mod(int d = 1) : dv(d) {}         bool operator()(int x) {return x % dv == 0;}     };      count3 = std::count_if(numbers.begin(), numbers.end(), f_mod(3));     cout << "Count of numbers pisible by 3: " << count3 << " ";     count13 = std::count_if(numbers.begin(), numbers.end(), f_mod(13));     cout << "Count of numbers pisible by 13: " << count13 << "  ";  // increase number of numbers again     numbers.resize(Size3);     std::generate(numbers.begin(), numbers.end(), std::rand);     cout << "Sample size = " << Size3 << " "; // using lambdas     count3 = std::count_if(numbers.begin(), numbers.end(),              [](int x){return x % 3 == 0;});     cout << "Count of numbers pisible by 3: " << count3 << " ";     count13 = std::count_if(numbers.begin(), numbers.end(),               [](int x){return x % 13 == 0;});     cout << "Count of numbers pisible by 13: " << count13 << " ";      // std::cin.get();     return 0; }
  输出:Sample size = 39 Count of numbers pisible by 3: 14 Count of numbers pisible by 13: 0  Sample size = 3900 Count of numbers pisible by 3: 1365 Count of numbers pisible by 13: 289  Sample size = 390000 Count of numbers pisible by 3: 129968 Count of numbers pisible by 13: 30393
  函数数指针、函数对象、Lambda表达式的使用,可以从以下几个方面来区别:
  1 距离:让定义位于使用的地方最近是一种最佳的选择。这是Lambda表达式的优势。函数对象是次优的选择,因为函数对象的类也可以定义在函数内部。最差的是函数指针了,距离最远。
  2 简洁:是指代码的简洁度。Lambda表达式的代码最简洁,函数指针次之,函数对象虽然相对于函数指针来说,可以实现状态数据的存储,但代码的简洁度最差。
  3 效率
  这三种方法的相对效率取决于编译器内联那些东西。函数指针方法阻止了内联(能够内联的代码,执行效率比较高),因为编译器传统上不会内联其地址被获取的函数,因为函数地址的概念意味着非内联函数。而函数对象和lambda通常不会阻止内联。
  4 功能
  lambda有一些额外的功能。具体地说,lambad可访问作用域内的任何动态变量;要捕获要使用 的变量,可将其名称放在中括号内。如果只指定了变量名,如[z],将按值访问变量;如果在名称前加上& , 如[&count],将按引用访问变量。[&]让您能够按引用访问所有动态变量,而[=]让您能够按值访问所有动态变 量。还可混合使用这两种方式,例如[ted, &ed]让您能够按值访问ted以及按引用访问ed ,[&, ted]让您能够按值访问ted以及按引用访问其他所有动态变量,[=,&ed]让您能够按引用访问ed以及按值访问其他所有动态变量。
  看下面的实例:// lambda1.cpp -- use captured variables #include  #include  #include  #include  #include  const long Size = 390000L;  int main() {     using std::cout;     std::vector numbers(Size);      std::srand(std::time(0));     std::generate(numbers.begin(), numbers.end(), std::rand);     cout << "Sample size = " << Size << " "; // using lambdas     int count3 = std::count_if(numbers.begin(), numbers.end(),  		      [](int x){return x % 3 == 0;});     cout << "Count of numbers pisible by 3: " << count3 << " ";     int count13 = 0;     std::for_each(numbers.begin(), numbers.end(),          [&count13](int x){count13 += x % 13 == 0;});     cout << "Count of numbers pisible by 13: " << count13 << " "; // using a single lambda     count3 = count13 = 0;     std::for_each(numbers.begin(), numbers.end(),          [&](int x){count3 += x % 3 == 0; count13 += x % 13 == 0;});     cout << "Count of numbers pisible by 3: " << count3 << " ";     cout << "Count of numbers pisible by 13: " << count13 << " ";      // std::cin.get();     return 0; }
  输出:Sample size = 390000 Count of numbers pisible by 3: 130144 Count of numbers pisible by 13: 29939 Count of numbers pisible by 3: 130144 Count of numbers pisible by 13: 29939
  用表格综合一下以上4项区别:
  表格数据:
  函数指针
  函数对象
  lambda表达式
  距离
  定位位置与使用位置
  最差
  次优
  最优
  简洁
  代码的简洁度
  次优
  最差
  最优
  效率
  可内联的代码效率要高
  不能内联
  可内联
  可内联
  功能
  额外功能
  可访问作用域内的任何动态变量
  ref
  StephenPrata:《C++ Primer Plus(6th 2011)》
  -End-

黑洞性质研究取得进展近日,中国科学院大学物理学院教授田雨和博士生陈前与暨南大学扬州大学和上海交通大学科研人员合作,在物理评论快报(PhysicalReviewLetters)上发表了题为Critica恐龙统治了地球1亿7千万年,却没进化成高等智慧生物,为什么?综述距今6500万年前,地球上的各处还是潮湿温热的。统治地球的霸主,还是体型硕大,力量充沛的恐龙。这个时候的地球,没有一处是文明的,每一天,血腥的捕猎事件还在各处上演。但是,一颗硕被弃太空的宇航员?真相到底是什么苏联宇航员谢尔盖克里卡列夫是很倒霉,在他去太空出差期间,祖国没有了,苏联解体了。因此,他就被莫名其妙的留在了太空,时间几乎长达一年。这个故事,你多半听过,它们通常把谢尔盖渲染成一位加利福尼亚海岸发现了一种以神话生物命名的稀有的深海龙鱼高鳍龙鱼是这个深海群中最稀有的物种。研究人员在为期一周的RVWesternFlyer探险中发现了这种罕见的龙鱼。(图片来源MBARI)海洋生物学家最近在加利福尼亚州蒙特雷湾进行了一科学家发现婴儿宇宙,我们有可能回到过去吗?作为自然界中的高等生物,我们一直都在探索我们的地球母亲,人到底从何而来?宇宙会迎来终点吗?这些问题我们一直都没有停下研究的步伐。古代,即使科学水平非常落后,人们也没有现在的航天器探旋理论太极64卦图中的旋子假说能否为弦理论解困?根据向罗生太极64卦图,他旋和自旋是宇宙间一切事物本性。从基本粒子原子结构等离子体收缩超导超流龙卷风类星体黑洞,到月亮地球太阳银河系其他星系星球,再到个人社会组织等。其运动都可以用南极冰盖下是什么?科学家持续61天勘探,第一次描绘了冰下世界南极洲无疑是世界上最神秘的大陆,由于接收的太阳辐射有限,这里常年被冰雪覆盖,是唯一没有人类定居的大陆。南极洲冰盖的平均厚度达到2160米,最厚的地方甚至达到4776米,这使得南极洲哈勃拍到银河系的未来,漂亮却隐藏陷阱,地球早就不适宜生存了哈勃太空望远镜拍摄到了银河系的未来,如此漂亮的现象,其实蕴藏着大量的陷阱,这是两个星系之间灾难碰撞的产物,银河系的未来也是如此,时间大约发生在40亿年后,银河系将与仙女座星系碰撞,第二地球开普勒22B被发现!专家却称一辈子都到不了头号周刊一直以来人们都在寻找和地球类似的星球,以防止地球不适宜人类居住时可以前往新的星球。此前科学家们也发现了很多和地球类似的星球,不过他们大部分是岩石行星,或者气态的行星,并不适首次成功!美太空公司直升机空中接住坠落火箭,过程让人捏把汗据英国卫报报道,一家总部位于美国加州的太空公司火箭实验室(RocketLab)在一次测试中成功地用直升机接住了一枚坠落的火箭,该公司首席执行官称这次测试有点像超音速芭蕾舞。报道称,古希腊天文学发达,比中国还要耀眼!为何如今找不到天文观测遗迹谈及世界天文学,古希腊天文学是绕不过去的话题,因为它有着让其他所有文明都高山仰止的天文成就。按照西方的说法,自2700年前起古希腊天文学开始神奇爆发,先是毕达哥拉斯认为地球是圆的,
直截了当,各专业人士对待撒泼问题,都用的什么做法?据环球日报日前报道,在美国一架飞机上,一女子试图破坏美国航空安全法案规定,企图自己拉开飞机舱门,在机组人员发现后试图阻止这一行为,被该女子的咬伤,然后这名发疯的女子就被空警控制,并美金不值钱了?如今美债有市无价,中国表示不陪你玩了由于美国现如今的钞能力把自己的经济搞垮了,以无限印钞刺激美国国内的经济增长,最后适得其反,货物膨胀导致美金越来越不值钱,国际上美债早已热度下降,美联社看似英明的大放水举措只能让现如南非发生了什么?当地发生暴乱,造成多人死亡,经济停滞自曼德拉总统上台后,南非就从一个发达国家变为了发展中国家,其经济和社会情况萎靡不振,到现如今,南非再次由于政府管理制度发生暴乱,南非前总统祖马由于蔑视法律被依法逮捕关押,当地人民由美国不让世卫自己的实验室,世卫再次将矛头调向中国,意义何在?现如今的美国,本土疫情没有得到控制,非但没有加大防疫力度,还把侧重点转向中国。前一阵子,美国联合澳大利亚向中国索要赔偿,其中的原因就是想把疫情爆发的矛头指向中国病毒研究所。早期全球中国移民成主力军,还想带走亿万资产?国家已出手整治大家也都知道,尤其是在以前的时候,我国的经济发展水平不行,尤其是相比西方的发达国家,所以很多富商富豪就会选择移民,找个发达的国家进行发展生活。说到移民这个话题。现在的移民有一部分追钟剑秋做虔诚的追逐光的画家展览海报导言2021年8月21日,由北京靳尚谊艺术基金会与中国油画学会共同主办意大利TIAC协会协办的艺术与自然意大利考察创作汇报展于北京隆福文化中心正式开展。本次展览是对北京靳尚都成坑的寿山石一位玩藏福建寿山石雕印章的朋友,由于经验不足,又常恐走宝,曾购入一件黄金黄都成坑所刻成的作品,误以为像石贩所说是上品田黄。事实上,二者外表十分相似,若不细心鉴别,容易混淆。价值方面冰雪的长津湖电影长津湖刚上映没多久其票房就已经达到了惊人的20多亿,为什么会有如此高的票房呢,因为那是真实的历史。71年前在朝鲜战争中,有个没有一声枪响的战役,其悲壮程度震惊了整个世界,那就是跨界营销新媒体营销节庆营销冰雪旅游营销百花齐放品橙旅游2020年年底,一则新疆昭苏县红衣女县长策马奔腾雪野的短视频被刷屏,事后,女县长在说到拍短视频初衷时提到希望这样的短视频能帮助一下昭苏的旅游关联行业从业者,争取一些冬季冰雪冷资源变热经济,冰雪旅游节事的迭代之路品橙旅游近日,在央视新闻告别2020特别节目直播报道中,央视记者王冰冰亮相于查干湖第十九届冰雪渔猎文化旅游节的夜幕中。她在晶莹剔透的冰钢琴上雀跃跳动,随之而来的是钢琴般的美妙旋律。冰雪旅游与保险品橙旅游年初,河北省张家口市崇礼区由密苑(张家口)旅游胜地有限公司经营的云顶滑雪场发生一起安全事故,导致一名男性滑雪者意外死亡,引起轩然大波。2020年12月初,在哈尔滨融创雪世界