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