添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
C++函数调用解耦-V1

C++函数调用解耦-V1

4 年前 · 来自专栏 可以走一辈子的开发之路

最近在敲代码的过程中,遇到了一个颇有意思的问题:

如何简单、干净、不留痕迹的完成模块A中函数funA调用模块B中的funB的过程?

首先解释下,什么叫“简单、干净、不留痕迹”。

一般来说funA调用funB最直接的方式无非是,在A文件中包含B的头文件,如果需要的话A库链接B库,然后就可以按如下方式直接调用:

void funA()
   funcB()

这种方式的最大问题是,模块A、B之间形成了强依赖,A知道了太多除funB以外的信息,而这些大多是非必须的。我们可以想象一下,funA如果需要调用funB,它只需要知道funB的参数列表与返回值即可,其他都是无关紧要的。

基于这样的“断舍离”视角,很自然会引申出一种解耦策略,使用一张映射表来保存函数对象,通过绑定来注册,然后在需要的时候调用。

using any_function = std::function<void(std::any)>;
class function_register
public:
	void regist(const std::string &key, const any_function& func);
	void run(const std::string &key, const std::any &);
private:
	std::unordered_map<std::string, any_function> function_hub;

定义了一个map,保存了any_function 事实上,any_function这个名字起得有点不要脸,当前的表示方式还无法涵盖任意函数类型,首先返回值只能是void,其次参数使用std::any把变参参数列表打包成了一个std::any,有点取巧,当然效率和简洁程度也有损失。这是目前使用的v1版,希望接下来有更简洁的版本。

void plus(const std::any&data)
	int a, b;
	std::tie(a, b) = std::any_cast<std::pair<int, int>>(data);
	std::cout << a << "+" << b << "=" << a + b << std::endl;
void plus_100(const std::any&data)
	int a = std::any_cast<int>(data);
	std::cout << a << "+" << 100 << "=" << a + 100 << std::endl;
class test_output
public:
	void ppp(const std::any &a)
		std::cout << std::any_cast<const std::string>(a) << std::endl;
int main()
	function_register fr;
	test_output to;
	fr.regist("plus", std::bind(&plus, std::placeholders::_1));
	fr.regist("plus_100", std::bind(&plus_100, std::placeholders::_1));
	fr.regist("plus_triple", [](const std::any& triple)
		int a, b;
		double c;
		std::tie(a, b, c) = std::any_cast<std::tuple<int, int, double>>(triple);
		std::cout << a << "+" << b << "+" << c << "=" << a + b + c << std::endl;
	fr.regist("test_output::ppp", std::bind(&test_output::ppp, &to, std::placeholders::_1));
	fr.run("plus", std::make_pair(1, 2));