所谓对象
,就是在内存中存在的具体实例。
那可调用对象
,就是可以像函数一样调用的对象。
Lambda
表达式最基本的可以调用的对象就是函数,而指向某个函数的函数指针,也是可调用的
首先仿函数是一个自定义的class实例
, 然后这个实例可以指定参数调用自己,实现像函数一样的行为
调用自己,指的是可以以圆括号加参数的形式, 像函数一行执行, 执行的函数就是这个示例对应的圆括号函数重载. 如:
// Less类型实现了圆括号的操作符重载,参数为int a, int b, 实现的功能是判断a是否小于b
class Less {
public:
bool operator()(int a, int b)
{
return a < b;
}
};
Less less; // 定义一个Less对象实例less, 则less实例就是仿函数
std::cout << less(0, 1) << std::endl; // 0 < 1, 输出1, 对应true
std::cout << less(100, 50) << std::endl; // 100不小于50, 对应false
std::cout << less(10, 10) << std::endl; // 10不小于10, 对应false
// 有一个外部函数, 用来过滤数据
template<Func>
std::vector<int> filter(Func&& func, const std::vector<int>& src);
// 假设需要筛选某个范围的值
std::vector<int> numbers{1, 4, 5, 2, 7, 8, 0};
// 使用仿函数
class Between {
public:
Between(int down, int up): down_(down), up_(up) {}
bool operator(int number) const
{
return down_ <= number && number <= up;
}
private:
int down_;
int up_;
};
// 筛选[1, 5]区间的整数并且筛选范围还可以使用变量来控制, 仿函数可以轻松实现,但是函数指针不行
std::vector<int> filtered = filter(Between(1, 5), numbers); // 1, 4, 5, 2
原生的函数,只能使用固定的参数,定义的形式确定后,调用的形式也是固定的,无法指定多余的参数, 所以在传统C时代,都会使用一个额外的void*
参数传递额外参数,且类型需要开发者自己保证安全
这是一个可以将同一调用规则的可调用对象使用统一类型封装的一个盒子,只要可调用对象的形式符合这个盒子的要求,就都可以放到这个盒子里,并且这个盒子还可以什么也不放(此时不可调用)
functional
放到列表或者映射中可以简单的包装普通函数,类静态函数,与原函数用法一样
int funcA();
std::function<void()> func = std::bind(funcA);
func(); // 与直接调用funcA()效果一样
可以将对象和成员函数绑定在一起,最为一个新的可调用对象,调用对象的参数形式与成员函数的参数保持一致
class Bird {
public:
void fly()
{
// ...
}
};
Bird some_bird;
Bird another_bird;
std::function<void()> bird1_fly = std::bind(&Bird::fly, &some_bird);
std::function<void()> bird2_fly = std::bind(&Bird::fly, &another_bird);
bird1_fly(); // 转换成了普通函数调用的形式,并且内部隐含了固定bird对象作为内部参数
bird2_fly();
除了可以将现有的成员函数变换形式, 也能将其他函数表换形式,适配目标调用形式
// 可调用目标的形式
std::function<bool(int)> filter_item;
// 我们有如下几个函数
bool less(int a, int b); // a < b
bool is_times(int a, int b); // a % b == 0
// 除了自定义仿函数将这几个函数再封装一层以外,我们可以使用bind来封装
// 1. bind less函数,并且a参数固定为100,b作为过滤参数, 过滤大于100的数
filter_item = std::bind(less, 100);
filter_item(10); // => 100 < 10 ? false, 100不小于10
filter_item(1000); // => 100 < 1000 ? true, 100小于1000
// 2. bind less函数,并且参数b固定100, a作为参数,过滤小于100的数
filter_item = std::bind(less, std::placeholders::_1, 100);
filter_item(10); // => 10 < 100 ? true, 10小于100
filter_item(1000); // => 1000 < 100 ? false, 1000不小于100
// 3. 是否4的倍数
filter_item = std::bind(is_times, std::placeholders::_1, 4);
filter_item(8); // true
filter_item(3); // false
// 4. 是否1000的因数
filter_item = std::bind(is_times, 1000);
filter_item(10); // true
filter_item(100); // true
filter_item(101); // false
匿名仿函数类,功能与仿函数一致, 但是可以直接使用代码块生成一个仿函数, 并且代码块也可以绑定函数参数以外的变量作为额外的调用参数,绑定外部变量不外部值绑定(拷贝一份到仿函数内部)和引用绑定(将外部对象的引用传入仿函数内部)
int upper = 100;
std::function<bool(int)> filter = [upper](int number) {
return number < upper;
};
upper = 50; // 重新绑定
filter = [upper](int number) {
return number < upper;
};
// 直接绑定引用
filter = [&upper](int number) {
return number < upper;
};
upper = 10;
filter(1); // 1 < 10 ? true
upper = 1;
filter(100); // 100 < 1 ? false