C++11 lambda表达式用法
Lambda表达式(匿名函数、Lambda函数)是现代C++在C ++ 11和更高版本中的一个新的语法糖,可以让我们快速便捷的创建一个函数。
[ capture-list ] ( params ) mutable exception attribute -> return-type { body }
capture-list:捕获列表,一般在Lambda表达式开头,捕获上下文中的变量,用逗号分隔。
params:参数列表,函数所需参数,写法同函数参数,但是不支持默认参数。若没有参数可连同"()"直接省略。
mutable:可变规格(修饰符),当捕获列表是以复制的形式捕获时,默认复制值为const,若指定mutable则可取消其常量性。
exception:异常说明,用于函数内部抛出异常。
attribute:声明属性。
return-type:返回值类型,可省略。
body:函数体。
捕获列表说明:lambda表达式的捕获列表精细控制了lambda表达式能够访问的外部变量,以及如何访问这些变量。
1).[]不捕获任何变量。
2).[&]以引用的方式捕获所有变量。
3).[=]以拷贝的方式捕获所有变量。
4).[=,&foo]按值捕获外部作用域中所有变量,并按引用捕获foo变量。
5).[var]表示值传递方式捕获变量var。
6).[this]捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,就默认添加此选项。捕获this的目的是可以在lamda中使用当前类的成员函数和成员变量。
auto lambda_test = [] {std::cout << "Hello, World!\n";}; lambda_test();
上例将打印字符的lambda函数赋给了lambda_test,然后直接调用函数。运行可得到结果"Hello,World!"
Lambda应用场景:当我们需要使用一次性函数时我们可以直接使用lambda函数,避免工程文件定义过多的非常用函数。
需注意,lambda表达式无法捕捉局部静态变量,如下例:
vector<function<void()>>fd; void func() { static int a = 1; auto f = []() { cout << a << endl; }; fd.emplace_back(f); a++; } int main() { func(); func(); func(); func(); fd[0](); fd[1](); fd[2](); fd[3](); return 0; }
vs2022输出如下
可以看到lambda未捕获任何值或引用,但是依然可用使用局部静态变量a,本人推测局部静态变量可被同作用域下的lambda默认引用捕获,即与下面情况相同
void func() { static int a = 1; auto f = [&p=a]() { cout << p << endl; }; fd.emplace_back(f); a++; }
括号内的内容可理解为 auto& p=a,p为a的引用。
及时上述lambda修改为[=]默认按值捕获,也不会按值捕获a的值,而是依然为引用捕获,即输出仍为全5,除非将lambda修改为如下:
void func() { static int a = 1; auto f = [p=a]() { cout << p << endl; }; fd.emplace_back(f); a++; }
需注意,lambda的初始化捕获(即上文中的[p=a] [&p=a])是c++14才有的,c++11中可以使用闭包类来代替lambda实现,例子如下:
//c++14 class Widget { //一些有用的类型 public: … bool isValidated() const; bool isProcessed() const; bool isArchived() const; private: … }; auto pw = std::make_unique<Widget>(); //创建Widget;使用std::make_unique … //设置*pw auto func = [pw = std::move(pw)] //使用std::move(pw)初始化闭包数据成员 { return pw->isValidated() && pw->isArchived(); };
//c++11 class IsValAndArch { //“is validated and archived” public: using DataType = std::unique_ptr<Widget>; explicit IsValAndArch(DataType&& ptr) : pw(std::move(ptr)) {} bool operator()() const { return pw->isValidated() && pw->isArchived(); } private: DataType pw; }; auto func = IsValAndArch(std::make_unique<Widget>());
这块有关的更详细的内容请查阅EffectiveModernCpp 条款32
参考文章:
https://paul.pub/cpp-lambda-function-bind/
https://blog.csdn.net/qq_37085158/article/details/124626913?spm=1001.2014.3001.5506