先来看一个例子:
#include <iostream>
std::function<int(int, int)> func;
int add(int a, int b) {
return a + b;
}
auto reduce = [](int a, int b) -> int { return a - b; };
struct Multi {
int operator()(int a, int b) {
return a * b;
}
};
class Divide {
public:
int operator()(int a,int b){
if (b == 0){
return 0;
}
return a /b;
}
};
int main() {
Multi multi;
Divide divide;
std::cout << multi(10,20) << std::endl;
std::cout << divide(10,20) << std::endl;
func = add;
std::cout << func(1,2) << std::endl;
func = reduce;
std::cout << func(1,2) << std::endl;
func = multi;
std::cout << func(1,2) << std::endl;
func = divide;
std::cout << func(1,2) << std::endl;
return 0;
}
在 C++11,引入了std::fucntion.
由于C++中定义方法的方式有很多(严格来说叫做可调用对象),在大型系统中传递对象和回调方法可能不是很方便.
因此引入了std::function,对各种可调用对象进行包装,以便于统一管理,这么说可能还是不直观,来分析一下.
int add(int a, int b) {
return a + b;
}
auto reduce = [](int a, int b) -> int { return a - b; };
struct Multi {
int operator()(int a, int b) {
return a * b;
}
};
class Divide {
public:
int operator()(int a,int b){
if (b == 0){
return 0;
}
return a /b;
}
};
上面几个方法定义的形式都是同一种:
int(int,int)
使用std:function<int(int,int)>
就可以将这种形式的方法包装起来:
std::function<int(int, int)> func = add;
std::function<int(int, int)> func = reduce;
std::function<int(int, int)> func = multi;
std::function<int(int, int)> func = divide;
std::function
是一个类模板,作用是包装可调用对象,可以包装除了类成员函数指针以外的所有可调用对象,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟它们的执行.
定义的格式如下:
std::function<函数类型>
std::function
可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用.
可调用对象有下面这些:
- 函数指针
- 一个具有operator()成员函数的类的对象
- 可被转换成函数指针的类对象
- 一个类成员函数指针
普通的回调函数
再来说一下回调函数的问题,我们使用回调函数的步骤一般如下:
- 定义一个普通函数,作为回调函数
- 将回调函数的地址注册给调用者
- 调用者在适当的时刻通过函数指针调用回调函数.
实现方式如下:
typedef void(*callback)(std::string msg);
void log(std::string msg){
std::cout << msg << std::endl;
}
void notifyFunc(callback f){
f("Hello World");
}
int main() {
notifyFunc(log);
return 0;
}
std::function 作为回调函数
void logInfo(const std::string& msg){
std::cout << msg << std::endl;
}
int main() {
std::function<void(const std::string)> callbackFunc = logInfo;
callbackFunc("Hello World");
return 0;
}