function函数的用法c语言,使用std::function作为函数入参

1. 关于std::function()

在C语言的时代,我们可以使用函数指针来吧一个函数作为参数传递,这样我们就可以实现回调函数的机制。到了C++11以后在标准库里引入了std::function模板类,这个模板概括了函数指针的概念

函数指针只能指向一个函数,而std::function对象可以代表任何可以调用的对象,比如说任何可以被当作函数一样调用的对象。

当你创建一个函数指针的时候,你必须定义这个函数签名(表征这个函数的入参,返回值等信息);同样的,当你创建一个std::function对象的时候,你也必须指定它所代表的可调用对象的函数签名。这一点可以通过std::function的模板参数来实现。

举个例子来说,如果要定义一个std::function对象func,这个对象可以表示任何有如下函数签名的可调用对象的,

bool(const std::unique_ptr)&, // C++11里面用来比较两个

const std::unique_ptr&) //std::unique_ptr对象的函数签名

你可以这么写,

std::function&,

const std::unique_ptr&)> func;

这是因为lambda表达式产生了可调用的对象,这个对象这里称做一个闭包(closure),可以保存在std::function对象里面。

closure(闭包)的定义是,一个函数和它所引用的非本地变量(非lambda表达式内部定义的变量)的一个集合。

2. 使用std::function作为函数入参

2.1 基于传值的方式传递参数

参看下面一段代码,实现了一个注册回调函数的机制,

#include

void registerCallBack(std::function);

入参std::function是一个模板类对象,它可以用一个函数签名为void()的可调用对象来进行初始化;上述实现里面是一个传值调用。我们来看一下它的调用过程,

// 方法(A)

registerCallBack([=]{

.... // 回调函数的实现部分

})

这里使用了lambda表达式作为函数的入参,正如前面所说的lambda表达式会生成一个匿名的闭包(closure),基于这个闭包构造了一个std::function的对象,然后通过传值调用的方式把这个对象传递registerCallBack函数中使用。

2.2 基于引用的方式传递参数

当然我们还可以如下实现这个注册函数,入参通过const引用的方式传递,这里的引用必须是const的,这是因为调用registerCallBack函数的地方生成了一个临时的std::function()对象,是一个右值,否则编译会报错。

//方法(B)

void registerCallBack(std::function const&)

这两者的区别就在于,在registerCallBack函数内部怎么使用这个入参,如果只是简单的调用一下std::func()类,那么两种都没有问题,可能使用引用的效率更高;如果register函数内部需要保存这个std::func(),并用于以后使用,那么方法A直接保存没有问题,方法B就必须做一次拷贝,否则方法B中,当临时的对象销毁时,有可能出现引用悬空的问题。

2.3 传值方式下的std::function对象保存

如果我们要在registerCallBack函数内部保存这个传入的function对象,我们可以使用转移操作std::move,这样的效率更高,

class CallBackHolder

{

public:

void registerCallBack(std::function func)

{

callback = std::move(func);

}

private:

std::function callback;

}

3. 类的成员函数作为函数入参

类的成员函数都会默认有个隐藏的this指针,所以不像普通的函数直接作为入参就可以了。

3.1 使用std::bind()和std::function来实现

std::function是通用的多态函数封装器,它的实例可以存储、复制以及调用任何可以调用的目标:函数,lambda表达式/bind表达式或其他函数对象,还有指向成员函数指针和指向数据成员指针;

std::bind接受一个函数(或者函数对象),生成一个重新组织的函数对象;

看下面一个例子,classA提供了一个注册函数,用来注册一个回调函数

class classA

{

typedef std::function callback_t;

...

void registCb(callback_t func)

{cbHandle = std::move(func);}

private:

callback_t cbHandle;

};

另一个类classB需要注册自己的一个成员函数作为回调函数到classA中,这里就可以使用std::bind函数来实现,

class classB

{

public:

classB(classA& cA)

{

cA.registCb(std::bind(&classB::handle, this, std::placeholders::_1));

}

};

bind函数中显示的传递classB的this指针作为第一个参数给回调函数;

std::placeholders:_1代表一个占位符,用于回调函数显式的入参;

Effective Modern C++中专门有一节解释过std::bind的方式比较繁琐,并且有时侯会有一些局限性,所以在引入了lambda表达式后就可以用lambda表达式来替代std::bind实现函数回调注册。

3.2 使用lambda表达式实现

使用lambda表达式的方式可以简化这一个过程,参看如下一段代码,classB注册一个成员函数作为回调函数到classA中,classA会保存这个回调函数(std::function对象)到成员变量中,用于后面使用,

#include

#include

#include

class classA

{

typedef std::function callback_t;

public:

classA() {}

~classA() {}

void handle(int i)

{

std::cout << "classA::handle" << std::endl;

cbHandle(i);

}

void registCb(callback_t func)

{cbHandle = std::move(func);}

private:

callback_t cbHandle;

};

class classB

{

public:

classB(classA& cA)

{

cA.registCb([this](int i){classB::handle(i);});

}

~classB() {}

void handle(int i)

{

std::cout << "classB, handle message" << i << std::endl;

}

};

int main()

{

classA testa;

classB testb(testa);

testa.handle(10);

}

lambda表达式中捕获了classB的this指针

使用std::move的方式保存function对象到classA中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个使用C语言实现std::bind和std::function的示例程序: ```c #include <stdio.h> #include <stdlib.h> // 定义一个函数指针类型 typedef int (*FuncPtr)(int, int); // 定义一个结构体,用于存储函数指针和绑定的参数 typedef struct { FuncPtr func; int arg1; int arg2; } BindData; // 定义一个函数类型,用于作为std::function的模板参数 typedef int (*FuncType)(int, int); // 定义一个函数,用于将绑定的参数和函数指针传递给std::function int callFunc(void* data, int arg) { BindData* bindData = (BindData*)data; return bindData->func(bindData->arg1, bindData->arg2 + arg); } // 定义一个函数,用于创建std::function对象 void* createFunction(FuncPtr func, int arg1, int arg2) { BindData* bindData = (BindData*)malloc(sizeof(BindData)); bindData->func = func; bindData->arg1 = arg1; bindData->arg2 = arg2; return (void*)bindData; } // 定义一个函数,用于销毁std::function对象 void destroyFunction(void* data) { BindData* bindData = (BindData*)data; free(bindData); } // 定义一个函数,用于测试std::bind和std::function int add(int a, int b) { return a + b; } int main() { // 使用std::bind绑定参数 auto add5 = std::bind(add, std::placeholders::_1, 5); printf("%d\n", add5(10)); // 输出15 // 使用std::function调用绑定了参数的函数 FuncType func = (FuncType)createFunction(add, 10, 5); printf("%d\n", func(3, callFunc(func, 2))); // 输出20 // 销毁std::function对象 destroyFunction((void*)func); return ; } ``` 注意:这只是一个示例程序,实际上C语言并没有std::bind和std::function这两个库函数

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值