c++ lambda表达式(匿名函数)的使用总结

#include <iostream>
using namespace std;

//[=] () mutable throw() -> int {}

/**
 * lambda expression
 * “Lambda 表达式”(lambda expression)是一个匿名函数,
 * Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),
 * 是一个匿名函数,即没有函数名的函数。
 * 
 * */

/**
 * 基本语法如下
 * [capture](parameters) mutable ->return-type{statement}
 * 
 * [capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;
 * (parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;
 * mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);
 * ->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号->一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;
 * {statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
 * 注意到,lamda表达式,与普通函数,最大的不同,在于拥有捕获列表。捕获列表有一下几种形式
 * 
 * [var]表示值传递方式捕捉变量var;
 * [=]表示值传递方式捕捉所有父作用域的变量(包括this);
 * [&var]表示引用传递捕捉变量var;
 * [&]表示引用传递方式捕捉所有父作用域的变量(包括this);
 * [this]表示值传递方式捕捉当前的this指针。
 * 匿名函数lambdb表达式相当于在函数内部又定义了一个函数,函数内部的lambdb匿名函数会引用这个函数的变量
 * 而普通情况下函数内部是不能再定义函数的
 * */

int main(int argc,char **argv){

    int m = 1;
    auto val_lamda = [=]{return m+1;};  //以传值的方式捕获m,假想lambda函数内部也有个和m一样的常量,捕获的瞬间外部的m把值传递给内部的m
    auto ref_lamda = [&]{return m+1;};  //以引用的方式捕获m,lambda函数内部操作的m和外部是一个m.

    cout<<"val_lamda:"<<val_lamda()<<endl; //2
    cout<<"ref_lamda:"<<ref_lamda()<<endl; //2

    m++;

    cout << "val_lamda:" << val_lamda() << endl; //2
    cout << "ref_lamda:" << ref_lamda() << endl; //3

    int val= 0;

    // 对于const的成员函数,修改非静态的成员变量,所以就出错了
    // auto const_val_lambda = [=](){ val = 3; }; wrong!!!
    
    // 对与mutable标识的lambda表达式,以值传递方式捕获的变量可以在表达式内部修改,但作用域仅限于表达式内部,外部变量的值不会被改变
    auto mutable_val_lambda = [=]() mutable {val = 3;cout<<val<<endl;/*3*/ };
    mutable_val_lambda();
    cout<<val<<endl; // 0

    // 而对于引用的传递方式,不会产生变量的拷贝副本,而只会改变引用的值,因此就不会报错了
    auto const_ref_lambda = [&]() { val = 4; };
    const_ref_lambda();
    cout << val << endl; // 4

    auto mutable_ref_lambda = [&]() mutable { val = 5; };
    mutable_ref_lambda();
    cout << val << endl; // 5

    int kk = 789;
    auto f = [kk] {cout<<kk<<endl;};
    f(); //输出789

    //[]不捕获任何外部变量,参数kk和外部的kk完全不一样
    auto ck = [](int kk){cout<<kk<<endl;}; 

    ck(654);   //654

    //也可以通过函数体{}后面的()传入参数,定义和调用放在一起了
    [](int kk) { cout << kk << endl; }(456);  //456 这里的kk和外部的kk是两回事
   
    //下面的kk变量还是789
    cout<<kk<<endl;
    
    //lambda表达式的简单嵌套
    int mm = [](int x) { return [](int y) { return y * 2; }(x) + 6; }(5);
    std::cout << "mm:" << mm << std::endl; //输出mm:16

   //多个参数
    std::cout << "nn:" << [](int x, int y) { return x + y; }(5, 4) << std::endl; //输出n:9

    //返回值是函数指针的嵌套
    //auto gFunc = [](int x) -> function<int(int)> { return [=](int y) { return x + y; }; };

    auto gFunc = [](int x) -> function<int(int)> { return [=](int y) { return x + y; }; };

    auto lFunc = gFunc(4);   //调用的外层lambda表达式匿名函数 x=4传进去,x=4的作用域在外层{},通过[=]捕获进入内层{}

    auto llFunc = lFunc(5); //lFunc是个函数调用外层lambda表达式返回的结果,是个函数function<int(int)>,其实就是内层的lambda表达式这个整体,5这个参数就是内层匿名函数的参数y,通过y传进内层{}

    //所以本质是这样的,4通过x=4传入,再被捕获,y=5只是传入,不是捕获。

    std::cout << llFunc << std::endl;  //打印结果是9
    
    //以下多个示例,读者自行分析吧。
    auto hFunc = [](const function<int(int)> &f, int z) { return f(z) + 1; };
    auto aa = hFunc(gFunc(7), 8);

    int a1 = 111, b = 222;
    auto func = [=, &b]() mutable { a1 = 22; b = 333; std::cout << "a:" << a1 << " b:" << b << std::endl; };

    func();
    std::cout << "a1:" << a1 << " b:" << b << std::endl;

    a1 = 333;
    auto func2 = [=, &a1] { a1 = 444; std::cout << "a:" << a1 << " b:" << b << std::endl; };
    func2();

    auto func3 = [](int x) -> function<int(int)> { return [=](int y) { return x + y; }; };

    std::function<void(int x)> f_display_42 = [](int x) { cout<<x<<endl; };
    f_display_42(44);
}

猜你喜欢

转载自blog.csdn.net/caokun_8341/article/details/82224613
今日推荐