文章目录
- 一、仿函数
- 二、Lambda表达式
- 三、bind
- 四、function
一、仿函数
仿函数:重载了操作符()
的类,也叫函数对象
特征:可以有状态,通过类的成员变量来存储;(有状态的函数对象称之为闭包)
样例:
class Add {
public:
void operator() (int count) {
i += count;
cout << "i:" << i << endl;
}
int operator() (int a, int b) {
return a + b;
}
int i = 0; // 状态
};
二、Lambda表达式
Lambda表达式是一种方便创建匿名函数的语法糖,简化函数对象的创建,常用于需要短小逻辑的场景(如 STL 算法)。
语法:
[捕获列表](参数列表) mutable -> 返回类型 { 函数体 }
- 捕获列表:定义如何捕获外部变量,本质是将外部变量转变为类的成员变量
[=]
:值捕获所有外部变量,只可读,不能修改[&]
:引用捕获所有外部变量,可读可写[a, &b]
:显示指定,值捕获a
,引用捕获b
mutable
:加上此关键字,允许修改值捕获的变量(值捕获的外部变量成为函数的状态,并不会改变实际的外部变量值)- 返回值类型:由于有类型推导,所以可以省略
底层原理:
编译器将 lambda 转换为一个仿函数,重载 operator()
。例如:
/*
int i = 0;
auto func = [i](int count) mutable -> void {
i++;
cout << "count:" << count << " i:" << i << endl;
};
*/
class LambdaFun {
public:
LambdaFun(int _i) : i(_i) {}
void operator() (int count) {
i++;
cout << "count:" << count << " i:" << i << endl;
}
private:
int i;
};
例子:
std::vector<int> nums = {3, 1, 4};
std::sort(nums.begin(), nums.end(), [](int a, int b) { return a > b; });
// 降序排序
三、bind
std::bind
是用来通过绑定可调用对象以及参数生成新的可调用对象,支持参数顺序调整和部分参数绑定。
用法:
#include <functional>
auto new_callable = std::bind(原函数, 绑定参数列表);
- 占位符:
std::placeholders::_1, _2, ...
表示未绑定的参数位置
底层原理:
编译器将 bind 转换为一个仿函数,重载 operator()
。例如:
// auto f = std::bind(add, 10, 20);
class BindFun {
public:
BindFun(function<int(int, int)> _fn, int _a, int _b) : fn(_fn), a(_a), b(_b) {}
int operator()() const {
return fn(a, b);
}
private:
function<int(int, int)> fn;
int a, b;
};
// auto f = std::bind(&Add::add, &tmp, 10, std::placeholders::_1);
class BindCFun {
public:
// 此处定义了一个类型别名Fn为指向Add类中参数为(int, int),返回值为int的成员函数的指针
typedef int (Add::*Fn)(int, int);
BindCFun(Fn _fn, Add *_c, int _a) : fn(_fn), c(_c), a(_a) {}
int operator()(int b) const {
return (c->*fn)(a, b);
}
private:
Fn fn;
Add *c;
int a;
};
样例:
-
绑定普通函数
int add(int a, int b) { return a + b; } auto f = std::bind(add, 10, std::placeholders::_1); int c = f(20); // c = 30
-
绑定类成员函数
class Add { public: int add(int a, int b) { return a + b; } }; Add tmp; auto f = std::bind(&Add::add, &tmp, 10, std::placeholders::_1); int c = f(20) // c = 30
四、function
std::function
是一个抽象了函数参数和返回值的类模板(多态函数包装器)。
用途:
把任意函数包装成一个对象,该对象可以保存、传递、复制。
其可以包装:普通函数、类的成员函数和静态成员函数、仿函数、lambda表达式、bind返回的函数对象。
头文件:<functional>
用法:std::function<返回值类型(参数类型列表)> func;
样例:
-
包装普通函数:
#include <functional> int add(int a, int b) { return a + b; } // 包装普通函数 std::function<int(int, int)> f_add = add; // f_add1 = &add 效果一样 int c = f_add(1, 2); // c = 3
-
包装类静态成员函数:
class StaticFunc { public: static int add(int a, int b) { return a + b; } }; // 包装类静态成员函数 std::function<int(int, int)> f_add = &StaticFunc::hello; int c = f_add(1, 2); // c = 3
-
包装态成员函数:
class Add { public: int add(int a, int b) { return a + b; } }; // 包装类成员函数 std::function<int(Add *, int, int)> f_add = &Add::hello; Add tmp; int c = f_add(&tmp, 1, 2); // c = 3
-
包装仿函数:
// 包装一中的仿函数Add std::function<void(int)> f_add1 = Add(); std::function<int(int, int)> f_add2 = Add(); f_add1(1); // 打印 i:1 f_add1(2); // 打印 i:3, 因为仿函数保存了状态i的值 int c = f_add2(1, 2); // c = 3
-
包装Lambda:
int i = 0; auto func = [i](int count) mutable -> void { i++; cout << "count:" << count << " i:" << i << endl; }; // auto 实际为编译器生成的匿名类型(非 std::function) // 等效的 std::function 类型为 std::function<void(int)> func(1); // 打印 count:1 i:1 func(1); // 打印 count:1 i:2 cout << i << endl; // 打印 0, 因为mutable关键字,所以不会修改外部变量实际的值
-
包装bind绑定的可调用对象
三中的样例
auto
可显示转换为:std::function<int(int)>
总结C++11中function、Lambda、bind之间的关系:
function
用来描述函数对象的类型;Lambda
表达式用来生成函数对象(可以访问外部变量的匿名函数);bind
也是用来生成函数对象(函数和参数进行绑定的形式生成)
参考:
- 【C++面试题】面试官:请简述function,lambda,bind之间的关系_哔哩哔哩_bilibili
- DeepSeek