这次要讲的是:C++11如何通过组合函数来简化我们的程序。关于组合函数,大家可能对这个概念有点陌生。组合函数是将N个一元函数组成一种更复杂的函数,每个函数的返回值作为参数传给下一个函数,直到传到最后一个函数结束。这种组合函数的能力可以使我们以一种更直观的方式去完成复杂的链式执行行为。例如有三个函数:

  1. int f(int x), int g(int y), int h(int z)
  2. 依次调用三个函数
  3. int a,b,c,parm;
  4. a = f(parm);
  5. b = g(a);
  6. c = h(b);
  7. 等价于 c = h(g(f(parm)));

  这两种方式在使用起来不够简洁方便,如果能把这些简单函数组合起来,就可以按简单函数的方式去调用了,更加直观和简洁。比如像这样调用:

  1. compose(f,g,h)(parm);

  这种方式调用不是更方便吗,这种方式把这些函数串在一起了,内部是一个接一个调用并得到最终结果。

在c++中如何实现这种组合函数的调用呢?想想我们应该怎么做吧。我们先分析一下这种组合函数的调用的特点:

  • 都是一元函数;因为返回值要做下个函数的入参,返回值只有一个结果。
  • 一元函数的入参和返回值都是同一种类型;因为返回值要做下个函数的入参。
  • 按顺序从前往后调用。

  通过上面的分析我们知道这种组合函数有个隐含的约束就是,返回值和入参必须相同,这也导致这些函数只能是一元函数。
如果希望有多个入参,则要通过变通的方式了,比如可以将一个结构体作为入参,类似于data_struct f(data_struct)来实现多个入参的问题。

  好了现在看看c++中是如何实现这种调用的吧。

  1. template <typename OuterFn, typename InnerFn>
  2. class Composed
  3. {
  4. public:
  5. explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}
  6.  
  7. public:
  8. template <typename Arg>
  9. auto operator()(Arg arg) -> decltype(declval<OuterFn>()((declval<InnerFn>()(declval<Arg>()))))
  10. {
  11. return m_outerFn(m_innerFn(arg));
  12. }
  13.  
  14. private:
  15. InnerFn m_innerFn;
  16. OuterFn m_outerFn;
  17. };
  18.  
  19. template <typename Function1, typename Function2>
  20. Composed<Function1, Function2> Compose(Function1 f1, Function2 f2)
  21. {
  22. return Composed<Function1, Function2>(f1, f2);
  23. }
  24.  
  25. template <typename Function1, typename Function2, typename Function3, typename... Functions>
  26. auto Compose(Function1 f1, Function2 f2, Function3 f3, Functions... fs)->decltype(Compose(Compose(f1, f2), f3, fs...))
  27. {
  28. return Compose(Compose(f1, f2), f3, fs...);
  29. }

写好了,再测试一下:

  1. int gt(int x)
  2. {
  3. return x;
  4. }
  5. int ht(int y)
  6. {
  7. return y;
  8. }
  9.  
  10. void TestCompose()
  11. {
  12. auto f1 = [](int a){return a + ; };
  13. auto g1 = [](int b){return b + ; };
  14. auto h1 = [](int c){return c + ; };
  15. auto I1 = [](int d){return d + ; };
  16. auto J1 = [](int e){return e + ; };
  17.  
  18. auto ret = Compose(f1, g1, h1)();
  19. ret = Compose(f1, g1, h1, I1)();
  20. ret = Compose(f1, g1, h1, I1, J1)();
  21. ret = Compose(f1, g1, h1, I1, J1, J1, J1)();
  22. ret = Compose([](int d){return d + ; }, [](int d){return d + ; })();
  23.  
  24. }

  通过测试程序我们可以看到,我们可以组合任意多个一元函数,这些一元函数可以是function也可以是lamda,它们之间彼此独立没有关联关系。这种组合是非常灵活的,也可以动态调整的。也许有人要问,这个东西有啥用啊,细想一下,它还是挺有价值的:

首先,它比原来的调用更加直观和简洁,其次它可以很方便的实现链式的函数调用,说到链式的函数调用,在做数据处理的时候比较有用,有可能需要对数据进行层层预处理,这些处理过程通过组合方式很容易实现,而且可以方便的增加或者减少处理函数,以及调换顺序,这是非常灵活的。

其次,它可以很容易做成责任链模式,它比动态多态实现的责任链模式更加强大,这个链条可以动态调整,调用函数之间彼此可以没有任何关系,没有继承这种强约束关系,使得我们可以灵活的实现责任链模式。我相信它的价值还有更多。

c++11 boost技术交流群:296561497,欢迎大家来交流技术。

(原创)C++11改进我们的程序之简化我们的程序(二)的更多相关文章

  1. (原创)C++11改进我们的程序之简化我们的程序(八)

    本次要讲的是如何通过泛型函数来简化我们的程序. 泛型函数除了之前介绍的一些优点外还有两个重要的优点 1.消除重复逻辑,提高程序的内聚性和健壮性 泛型函数在某种程度上用来弥补泛型类型的不足.通过泛型类型 ...

  2. C++11改进我们的程序之简化我们的程序1

    C++11改进我们的程序之简化我们的程序(一) C++11在很多方面可以简化我们的程序开发,我会在“简化我们的程序”这一系列的博文中一一讲到,敬请关注.这次要讲的是:C++11如何通过获取函数模板的返 ...

  3. (原创)C++11改进我们的程序之简化我们的程序(四)

    这次要讲的是:c++11统一初始化.统一begin()/end()和for-loop循环如何简化我们的程序 初始化列表 c++11之前有各种各样的初始化语法,有时候初始化的时候还挺麻烦,比较典型的如v ...

  4. (原创)C++11改进我们的程序之简化我们的程序(三)

    这次要讲的是:C++11如何通过auto.decltype和返回值后置来简化我们的程序. auto和c#中的var类似,都是在初始化时自动推断出数据类型.当某个变量的返回值难于书写时,或者不太确定返回 ...

  5. (原创)C++11改进我们的程序之简化我们的程序(一)

    C++11在很多方面可以简化我们的程序开发,我会在“简化我们的程序”这一系列的博文中一一讲到,敬请关注.这次要讲的是:C++11如何通过获取函数模板的返回值类型来简化我们的程序.在谈到简化之前,我们先 ...

  6. (原创)c++11改进我们的模式之改进代理模式,实现通用的AOP框架

    c++11 boost技术交流群:296561497,欢迎大家来交流技术. 本次要讲的时候如何改进代理模式,具体来说是动态代理模式,动态代理模式一般实现AOP框架,不懂AOP的童鞋看这里.我前面的博文 ...

  7. (原创)c++11改进我们的模式之改进命令模式

    模式虽然精妙,却难完美,比如观察者模式中观察者生命周期的问题:比如访问者模式中循环依赖的问题等等:其它很多模式也存在这样那样的一些不足之处,如使用场景受限.实现复杂.不够简洁.不够通用等.但我觉得不足 ...

  8. (原创)c++11改进我们的模式之改进访问者模式

    本次讲c++11改进我们的模式之改进访问者模式 访问者模式是GOF23个设计模式中比较复杂的模式之一,但是它的功能也很强大,非常适合稳定的继承层次中对象的访问,可以在不修改被访问对象的情况下,动态添加 ...

  9. (原创)C++11改进我们的程序之简化我们的程序(七)

    这次要讲的内容是:c++11中的tuple(元组).tuple看似简单,其实它是简约而不简单,可以说它是c++11中一个既简单又复杂的东东,关于它简单的一面是它很容易使用,复杂的一面是它内部隐藏了太多 ...

随机推荐

  1. java开发微信模板消息推送

    发布时间:2018-12-12   技术:springboot+maven   概述 该demo主要涉及微信模板消息推送功能, 详细 代码下载:http://www.demodashi.com/dem ...

  2. 解决 Class not found和Base table or view not found: 1051 问题

    1.解决class not found的方法: 如果你用的是homestead虚拟机,那么,你要到虚拟机下执行: composer dump-autoload 2.解决Base table or vi ...

  3. ajax post方式下载后台传来的文件

    参考:http://stackoverflow.com/questions/16086162/handle-file-download-from-ajax-post $.ajax({ type: &q ...

  4. Golang 要点汇总

    Golang有很多非常强大的用法,本文对网上的一些文章做一个简单的汇总,供以后翻阅. 1,Constant的用法 https://splice.com/blog/iota-elegant-consta ...

  5. mysql之limit m,n

    limit是mysql的语法 select * from table limit [m],n; 其中,m—— [m]为可选,如果填写表示skip步长,即跳过m条. n——显示条数.指从第m+1条记录开 ...

  6. java mongodb 基础系列---查询,排序,limit,$in,$or,输出为list,创建索引,$ne 非操作

    官方api教程:http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-java-driver/#getting-started ...

  7. 浅谈 iOS 与 H5 的交互- JavaScriptCore 框架

    前言 小的作为一个iOS程序猿,可能研究JavaScript以及H5相关的知识并不是为了真正的要去转行做这一方面,其实更多的为了要研究OC中的JavaScriptCore框架,JavaScriptCo ...

  8. 进阶之路(基础篇) - 005 模拟PWM波控制引脚

    /********************************* 代码功能:输出PWM波控制引脚 使用函数: 创作时间:2016*10*07 作者邮箱:jikexianfeng@outlook.c ...

  9. linux达人养成计划学习笔记(三)—— 帮助命令

    一.帮助命令man 1.基本使用方法: man 命令 #获取指定命令的帮助选项: -f 查看命令拥有的帮助级别 相当于whatis,也可以使用whereis来查询 -num 调用对应等级的帮助文件 - ...

  10. 使用Cordova搭建Andoid和iOS开发环境

    最近在了解cordova  ,下面的分享出来  大家可以看看,  我 有空也按照这个写写demo 1.下载node.js,进行安装 https://nodejs.org/en/ 2.安装cordova ...