博客《C++11 新特性总结》描述了一些 C++11 带来的新的特性,但是不够全面。所以写该博客做一个简要补充。在实际工作中,std::function 经常用来实现回调函数。
一、C++11为什么要引入std::function?
在 C++03 的时代,是使用函数指针来把一个函数作为参数传递,这样我们就可以实现回调函数的机制。程序设计,特别是程序库设计时,经常需要涉及到回调,如果针对每种不同的可调用对象单独进行声明类型,代码将会非常散乱,也不灵活。
所以 C++11 就引入了std::function
类模板,这是一种通用、多态的函数封装,在头文件<functional>
定义。std::function
的实例可以对任何可以调用的目标对象进行存储、复制和调用操作。而函数指针只能指向一种类型的函数,并且函数指针也是类型不安全的。
可调用对象(callable object)包括:
- 函数
- 函数指针
- lambda 表达式
- bind 创建的对象
- 重载了函数调用运算符的类(仿函数)
二、概述
对std::function
最简单的理解就是:std::function
实现了函数的存储,即先将可调用实体保存起来,在需要的时候再调用。
关于可调用对象转换为std::function
对象需要遵守以下两条原则:
- 转换后的
std::function
对象的参数能转换为可调用对象的参数; - 可调用对象的返回值能转换为
std::function
对象的返回值。
std::function
可以绑定全局函数,静态函数,但是绑定类的成员函数时,必须要借助std::bind
的帮忙。
使用者需要注意,它不能被用来检查相等或者不相等,但是可以与 NULL 或者 nullptr 进行比较。
三、函数原型
template< class R, class... Args >
class function<R(Args...)>
- R 是返回值类型。
- Args 是函数的参数类型。
定义一个std::function
对象很简单,就是将可调用对象的返回值类型和参数类型作为模板参数传递给std::function
模板类。比如:
// std::function<函数类型>
std::function<void(int)> functional1;
std::function<int(int,int)> functional2;
四、示例
std::function
的使用有多态和万总归一的感觉,示例如下:
#include <iostream>
#include <functional>
// 普通函数
int testFun(int a, int b) {
return a + b;
}
// Lambda表达式
auto lamdaExps = [](int a, int b) {
return a + b;
};
// 仿函数
class Functor {
public:
int operator()(int a, int b) {
return a + b;
}
};
// 1.类成员函数
// 2.类静态成员函数
class TestClass
{
public:
int classMemberFun(int a, int b) { return a + b; }
static int staticMemberFun(int a, int b) { return a + b; }
};
int main() {
// 普通函数
std::function<int(int, int)> functional = testFun;
int ret = functional(10, 10);
std::cout << "普通函数:" << ret << std::endl;
// 普通函数指针
functional = &testFun;
ret = functional(10 ,20);
std::cout << "普通函数指针:" << ret << std::endl;
// Lambda表达式
functional = lamdaExps;
ret = functional(10, 30);
std::cout << "Lambda表达式:" << ret << std::endl;
// 仿函数
Functor testFunctor;
functional = testFunctor;
ret = functional(10, 40);
std::cout << "仿函数:" << ret << std::endl;
// 类成员函数(使用std::bind绑定类成员函数)
TestClass testObj;
functional = std::bind(&TestClass::classMemberFun, testObj, std::placeholders::_1, std::placeholders::_2);
ret = functional(10, 50);
std::cout << "类成员函数:" << ret << std::endl;
// 类静态成员函数
functional = TestClass::staticMemberFun;
ret = functional(10, 60);
std::cout << "类静态成员函数:" << ret << std::endl;
return 0;
}
可见std::function
的使用其实是很简单的,只要创建一个函数或者类对象,并传入相应的参数就可以存储任何具有相同返回值和参数的可调用对象,在调用的时候直接将std::function
对象加上 () 或加上相应参数就可以调用存储在其中的可调用实体。结果如下所示:
普通函数:20
普通函数指针:30
Lambda表达式:40
仿函数:50
类成员函数:60
类静态成员函数:70
参考: