C++ 组合函数

来源:互联网 发布:51单片机led交通灯程序 编辑:程序博客网 时间:2024/05/16 09:14

组合函数是将N个一元函数组成一种更复杂的函数,每个函数的返回值作为参数传给下一个函数,直到传到最后一个函数结束。这种组合函数的能力可以使我们以一种更直观的方式去完成复杂的链式执行行为。例如有三个函数:

int f(int x), int g(int y), int h(int z)依次调用三个函数int a,b,c,parm; a = f(parm); b = g(a); c = h(b); 等价于 c = h(g(f(parm)));

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

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

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

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

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

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

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

template <typename OuterFn, typename InnerFn>class Composed{public:explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}public:template <typename Arg>auto operator()(Arg arg) -> decltype(declval<OuterFn>()((declval<InnerFn>()(declval<Arg>())))){return m_outerFn(m_innerFn(arg));}private:InnerFn m_innerFn;OuterFn m_outerFn;};template <typename Function1, typename Function2>Composed<Function1, Function2> Compose(Function1 f1, Function2 f2){return Composed<Function1, Function2>(f1, f2);}template <typename Function1, typename Function2, typename Function3, typename... Functions>auto Compose(Function1 f1, Function2 f2, Function3 f3, Functions... fs)->decltype(Compose(Compose(f1, f2), f3, fs...)){return Compose(Compose(f1, f2), f3, fs...);}

测试代码:

void TestCompose(){    auto f1 = [](int a){return a + 1; };    auto g1 = [](int b){return b + 2; };    auto h1 = [](int c){return c + 3; };    auto I1 = [](int d){return d + 4; };    auto J1 = [](int e){return e + 5; };    auto ret = Compose(f1, g1, h1)(3);    ret = Compose(f1, g1, h1, I1)(3);    ret = Compose(f1, g1, h1, I1, J1)(3);     ret = Compose(f1, g1, h1, I1, J1, J1, J1)(3);    ret = Compose([](int d){return d + 4; }, [](int d){return d + 5; })(3);}

对于compose那里之前的代码在gcc下编译不过,原因是因为GCC和vs2013对于变参的展开规则不太一样导致的,GCC的展开规则更严格。

完整测试代码:

#include <vector>#include <iostream>using namespace std;template <typename OuterFn, typename InnerFn>class Composed{public:explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}public:template <typename Arg>auto operator()(Arg arg) -> decltype(declval<OuterFn>()((declval<InnerFn>()(declval<Arg>())))){return m_outerFn(m_innerFn(arg));}private:InnerFn m_innerFn;OuterFn m_outerFn;};template <typename Function1, typename Function2>Composed<Function1, Function2> Compose(Function1 f1, Function2 f2){return Composed<Function1, Function2>(f1, f2);}template <typename Function1, typename Function2, typename Function3, typename... Functions>auto Compose(Function1 f1, Function2 f2, Function3 f3, Functions... fs)->decltype(Compose(Compose(f1, f2), f3, fs...)){return Compose(Compose(f1, f2), f3, fs...);}void TestCompose(){auto f1 = [](int a){return a + 1; };auto g1 = [](int b){return b + 2; };auto h1 = [](int c){return c + 3; };auto I1 = [](int d){return d + 4; };auto J1 = [](int e){return e + 5; };auto ret = Compose(f1, g1, h1)(3);ret = Compose(f1, g1, h1, I1)(3);cout << ret << endl;ret = Compose(f1, g1, h1, I1, J1)(3);cout << ret << endl;ret = Compose(f1, g1, h1, I1, J1, J1, J1)(3);cout << ret << endl;ret = Compose([](int d){return d + 4; }, [](int d){return d + 5; })(3);cout << ret << endl;}int main(){TestCompose();system("pause");return 0;}



0 0