1. lambda
1.1 表达式语法
lambda对象是一个匿名函数对象,可以定义在函数内部,用auto或者模板参数接收。
表达式格式:
cpp
[capture-list] (parameters)-> return type {function boby }
- capture-list:捕捉列表,可以捕获
lambda外部的变量供其使用,不可省略 - parameters:参数列表,
可省略 - return type:返回值类型,
可省略(编译器推导) - function boby:函数体,
不可省略
cpp
int main()
{
//省略参数和返回值
auto eg1 = []{cout << "hello, world" << endl;};
eg1();
}
正常运行:

1.2 捕捉列表
分为显式,隐式和混合捕捉,传参支持传值和传引用:
显式捕捉:和传参方式类似,传值捕捉不可修改(const),传引用捕捉可以修改:
cpp
//显式捕捉
int main()
{
int x = 0, y = 1, z = 2;
auto eg2 = [&x, y, z]
{
++x;
// ++y; //不可修改
cout << x << " " << y << " " << z << endl;
};
eg2();
}
++y报错信息:

隐式捕捉 :传值捕捉(=),不可修改;传引用捕捉(&)。会自动捕捉lambda中用到的外部变量:
cpp
//隐式捕捉
int main()
{
int x = 1, y = 2, z = 3;
auto eg3 = [=]
{
cout << x << " " << y << " " << z << endl;
};
eg3();
auto eg4 = [&]
{
x += 10;
y += 10;
z += 10;
cout << x << " " << y << " " << z << endl;
};
eg4();
}
混合捕捉 :显式和隐式捕捉同时使用,第一个元素必须是隐式,且不可冲突(=后无值捕捉,&后无引用捕捉):
cpp
//混合捕捉
int main()
{
int x = 1, y = 2, z = 3;
auto eg5 = [&, z]
{
x -= 10;
y -= 10;
cout << x << " " << y << " " << z << endl;
};
eg5();
}
补充:
全局lambda的捕捉列表必须为空- 传值捕捉默认const,但可以加
mutable关键字取消常量属性,但仅修改lambda内部临时参数,不会影响外部实参
cpp
int main()
{
int x = 1, y = 2, z = 3;
//C++20中,mutable存在时省略参数列表的()是非法的
auto eg6 = [=]() mutable
{
x += 1;
y += 1;
z += 1;
cout << x << " " << y << " " << z << endl;
};
eg6();
}
输出:

1.3 原理和应用
- 原理:底层是
仿函数对象,通过捕捉列表传入的参数构造仿函数类,再调用对应函数并传入参数列表 - 应用:定义可调用对象(函数) / 线程 / 智能指针...
底层模拟展示:
cpp
int Add(int a, int b)
{
return a + b;
}
int main()
{
int x = 1, y = 2, z = 3;
auto eg7 = [x](int a, int b)
{
Add(a, b);
};
eg7(y, z);
}
//底层为类似的仿函数对象:
class LambdaClass_eg7 //类名按照一定规则生成
{
private:
int _x;
public:
LambdaClass_eg7(int x)
:_x(x)
{}
void operator()(int a, int b) const //不嫩修改x
{
Add(a, b);
}
};
2. 包装器
2.1 function
官方文档:
- 介绍:
std::function是类模板,实例出的对象可以存储其他可调用对象(函数指针/仿函数/lambda/bind等),不可为空,否则会抛出std::bad_function_call的异常 - 头文件:
<functional> - 优势:统一类型,方便声明/调用可调用对象
包装示例:
cpp
//function包装器
void eg1()
{
cout << "eg1" << endl;
}
struct Less
{
bool operator()(int x, int y)
{
cout << "less()" << " ";
return x < y;
}
};
class Student
{
private:
string _name;
int _no;
public:
Student(string name, int no)
:_name(name)
,_no(no)
{}
void Print() const
{
cout << _name << " " << _no << endl;
}
static int add(int x, int y) const
{
cout << "mzh::static_add" << " ";
return x + y;
}
};
int main()
{
function<void()> Func0 = eg1; //包装函数
function<bool(int, int)> Func1 = Less(); //包装仿函数
function<int(int, int)> Func2 = [](int x, int y){ cout << "lambda" << " "; return x - y;}; //包装lambda
function<void(Student*)> Func3 = &Student::Print; //包装类内成员函数(内部走->*)
function<void(Student&)> Func4 = &Student::Print; //包装类内成员函数(内部走.*)
function<int(int, int)> Func5 = &Student::add; //包装类内静态成员函数
int x = 1, y = 10;
Func0();
cout << Func1(x, y) << endl;
cout << Func2(x, y) << endl;
Student s1 = {"LiHua", 20250101};
Func3(&s1);
Func4(s1);
cout << Func5(x, y) << endl;
return 0;
}
输出:

统一包装可调用对象的例子(用function包装器代替if-else):
cpp
class Solution {
public:
int evalRPN(vector<string>& tokens)
{
stack<int> st;
map<string, function<int(int, int)>> FuncStr =
{
{"+", [](int x, int y){return x + y;}},
{"-", [](int x, int y){return x - y;}},
{"*", [](int x, int y){return x * y;}},
{"/", [](int x, int y){return x / y;}}
};
for(auto& s : tokens)
{
if(FuncStr.count(s))
{
int right = st.top();
st.pop();
int left = st.top();
st.pop();
st.push(FuncStr[s](left, right));
}
else
{
st.push(stoi(s));
}
}
return st.top();
}
};
2.2 bind
- 介绍:bind是一个
函数模板(函数适配器),可以在包装函数的同时调整参数个数和顺序 - 头文件:
<functional>
调用bind:
cpp
auto newCallable = bind(callable,arg_list);
- newCallable:包装
callable的可调用对象 - callable:可调用对象(在调用
newCallable时调用) - arg_list:参数列表,可能包含
placeholders::_n,用来指代newcallable中对应位置的参数(eg:第一个参数_1 / 第二个_2 / ...),剩余参数死绑定 - 参数在bind所在行发生
值拷贝,后续修改参数不会作用于newCallable
使用示例 / 应用(复利计算):
cpp
bind绑定
namespace bind
{
using placeholders::_1;
using placeholders::_2;
using placeholders::_3;
int Sub(int a, int b)
{
return a - b;
}
class Culculate
{
private:
int _x = 5;
int _y = 2;
public:
int Plus1()
{
return _x + _y;
}
int Plus2(int x, int y)
{
return x + y + _x + _y;
}
};
int main()
{
auto sub1 = bind(Sub, _1, _2); //绑定函数
cout << sub1(10, 2) << endl; //8
auto sub2 = bind(Sub, _2, _1); //修改参数顺序
cout << sub2(10, 2) << endl; //-8
auto sub3 = bind(Sub, _1, 100); //绑死固定参数(常用)
cout << sub3(20) << endl; //-80
Culculate c1;
function<int()> func1 = bind(Culculate::Plus1, c1); //固定对象
function<int(int, int)> func2 = bind(Culculate::Plus2, Culculate(), _1, _2); //固定对象
cout << func1() << endl; //7
cout << func2(10, 20) << endl; //37
//应用:和function搭配,复利计算(通过绑死参数实现计算不同金额在指定期限和利率下的利润)
auto CpInterest = [](double rate, double money, double year)->double
{
double ret = money;
for(int i=0; i<year; ++i)
{
ret += ret * rate;
}
return ret - money;
};
function<double(double)> f1 = bind(CpInterest, 0.015, _1, 3);
function<double(double)> f2 = bind(CpInterest, 0.015, _1, 5);
function<double(double)> f3 = bind(CpInterest, 0.025, _1, 10);
function<double(double)> f4 = bind(CpInterest, 0.035, _1, 30);
cout << f1(1000000) << endl;
cout << f2(1000000) << endl;
cout << f3(1000000) << endl;
cout << f4(1000000) << endl;
return 0;
}
}
输出:

感谢阅读,我们下篇文章见。