组合函数是将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
class Composed
{
public:
explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}
public:
template
auto operator()(Arg arg) -> decltype(declval()((declval()(declval()))))
{
return m_outerFn(m_innerFn(arg));
}
private:
InnerFn m_innerFn;
OuterFn m_outerFn;
};
template
Composed Compose(Function1 f1, Function2 f2)
{
return Composed(f1, f2);
}
template
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
#include
using namespace std;
template
class Composed
{
public:
explicit Composed(OuterFn outerFn, InnerFn innerFn) :m_outerFn(outerFn), m_innerFn(innerFn) {}
public:
template
auto operator()(Arg arg) -> decltype(declval()((declval()(declval()))))
{
return m_outerFn(m_innerFn(arg));
}
private:
InnerFn m_innerFn;
OuterFn m_outerFn;
};
template
Composed Compose(Function1 f1, Function2 f2)
{
return Composed(f1, f2);
}
template
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;
}