C++ 组合函数

本文介绍了一种在C++中实现组合函数的方法,通过模板元编程将多个一元函数串联成一个复杂函数,实现了简洁直观的链式调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

组合函数是将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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值