浅析std::function & std::bind
本文最后更新于:2022年2月1日 晚上
前情提要
众所周知,函数(Function)
封装了一系列可复用的操作集合,是各类编程语言中非常重要的概念
在C++
中,除了普通函数,还增加了仿函数(Functor)
,又称为函数对象
,实际上是重载了函数调用运算符operator()
的类
而C++11
中新增的lambda
表达式其实就是匿名Functor
这些统称为可调用对象(callable entity)
:
普通函数:
1
int add(int a, int b){return a + b;}
lambda
表达式:1
auto mod = [](int a, int b){ return a % b;}
函数对象类:
1
2
3
4
5struct divide{
int operator()(int denominator, int divisor){
return denominator/divisor;
}
};
問題点
以上三种可调用对象虽然调用形式都是 int(int,int)
但是定义形式五花八门,导致很难用统一的方式传递或保存
如果再遇到类成员函数,如何声明和调用,更是令人头大
大一统:平权衡,正度量,调轻重
天下分久必合,合久必分
是时候来统一度量衡了
std::function
std::function
是一个可调用对象包装器,是一个类模板,可以容纳所有可调用对象,用统一的方式处理函数和仿函数,并允许保存和延迟它们的执行
例如:
1 |
|
这样便可以舒适地定义、存储与调用一切可调用对象
了
如果这还不酷,什么是酷?—— 《Effective C++中文版(第三版)》p175
等一下
ちょっと待って,我刚刚是不是说了“一切”
我是不是忘了什么
什么呢
成员函数
成员函数的传递与调用一直是一个令人头疼的问题
但只要抓住其与普通函数的区别便可以一击毙命
成员函数 vs 普通函数
成员函数属于类,且可以使用成员变量(非static函数)
而成员变量依赖于具体实例
在不明确具体实例的情况下,成员函数没有办法正确执行
正是因为如此,成员函数其实是有一个隐含参数的(指向具体实例指针)
1 |
|
所以在调用成员函数时,必须想办法提供具体实例的指针
How
普通调用时,我们可以采用 .*
或者 ->*
运算符
但是在std::function
对象中,更为简便
直接具象为第一个参数
1 |
|
如果你不想在调用时绑定实例,也可以通过std::bind
函数在定义时绑定
1 |
|
这样就把对象a
的地址绑定到了函数对象func
的第一个参数上(从三个参数变成了两个参数)
顺便一提,std::bind
其实是将对象进行了拷贝
也就是说,如果对象a
销毁,func
照样可以正常调用
如果想将拷贝改为引用,可以采用ref(a)
形式
lambda
其实,调用std::bind
进行绑定还是有些麻烦的
毕竟,只有”懒”,才能推动自动化
lambda
其实本身就是为了简化函数定义而存在的
而且其本质是重载了operator()
的匿名函数对象类
所以在传递给std::function
时,是一个对象,也就无需额外传递实例信息
1 |
|
如果需要其余变量或者所在类的成员变量,可以通过lambda
的捕获列表传递
peace