一. lambda表达式

(一)语法定义[capture](paramters) mutable ->returnType{statement}

  1.[capture]:捕获列表

  (1)lambda函数只能捕获父作用域中的局部变量或形参。而捕获非父作用域或静态变量则会出错。(这里的父作用域指的是包含lambda函数的语句块,如main函数作用域)

    ①[]:表示不捕获;[=]和[&]:分别表示按值和按引用捕获所有父作域变量(包括this);

    ②[var]、[&var]分别表示按值和按引用捕获var。注意,默认是无法修改按值捕获的变量的值(因为lambda表达式的operator()默认为const)。

    ③[=,&foo]:表示按引用捕获foo变量,按值捕获父作用域中所有其它变量。

    ④[this]:捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样访问权限。捕获this的目的是可以在lambda中会使用当前类的成员函数和成员变量。

  (2)注意事项:

    ①捕获列表不允许变量重复传递。如[=,a]、[&,&this]其中的a和this都被重复传递。

    ②lambda表达式的按值捕获,是在声明lambda表达式的一瞬间就被复制了如果希望lambda表达式在调用时能即时的访问外部变量,应该使用按引用捕获

    ③默认情况下,按值捕获的变量是不可以被修改的,因为lambda表达式的operator()是个const函数。

    ④lambda不能捕获非父作用域变量或static变量。即它们不能被进入捕获列表中,但可在lambda的函数体内直接访问。

    2.(parameters):参数列表。

  (1)与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号()一起省略。

  (2)参数列表不支持默认值,也不支持可变参数。所有的参数必须有参数名。

  (3)C++14中,参数类型可以声明为auto类型

    3.mutable默认下,lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空)

    4.returnType返回值类型。用追踪返回类型形式声明函数的返回类型。在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行自动推导。如果没有return语句则返回void。

    5.{statement}函数体。内容与普通函数一样,除了可以使用参数之外,还可以使用所有捕获的变量。

(二)lambda表达式与仿函数

第17课 lambda表达式 

    1. 仿函数是编译器实现lambda表达式的一种方式。在现阶段,通常编译器都会把lambda表达式转化成为一个仿函数对象。因此,在C++11中,lambda可以视为仿函数的一种等价形式或叫“语法糖”。

    2. 两者虽然在语法层面上不同,但却有着相同的内涵为——都可以捕捉一些变量作为初始状态并接受参数进行运算。

    3. lambda表达式在C++11中被称为闭包类型(Closure Type),可以认为是个仿函数,带有const属性的operator()它的捕获列表捕获的任何外部变量最终均会变为仿函数的成员变量。由闭包类型定义的对象称为“闭包”(是个右值)。

  4. 没有捕获变量的lambda表达式可以直接转换为函数指针,而捕获变量的lambda表达式则不能转换为函数指针

【编程实验】lambda初体验

#include <iostream>

using namespace std;

int gVal = 0;

//捕获this指针
class Test
{
private: 
    int i = 0;
public:
    void func(int x, int y)
    {
        int a = 0;
        //auto lamb1 = [] {return i; }; //error,无捕获列表。
        //auto lamb2 = [&i] {return i; }; //error, 不能捕获父作用域(func域)以外的变量(i)
        auto lamb3 = [=] {return i; }; //ok,按值捕获(含this指针),因此可以访问类中的成员变量(i)。
        auto lamb4 = [&] {return i + x + a; }; //ok,按引用捕获(含this指针),可以使用类中的成员变量(i)
                                               //同时,也捕获到形参x和局部变量a。
        auto lamb5 = [this] {return i; };  //ok,直接捕获this指针。

        auto lamb6 = [] {return gVal++; }; //ok,可以使用直接使用全局变量,无须也不能捕获它。
    }
};

int main()
{
    int a = 3;
    int b = 4;

    //1. lambda表达式初体验
    auto lamb1 = [] {};   //最简单的lambda表达式

    auto lamb2 = [=] {return a + b; };//省略参数列表和返回类型
    cout << lamb2() << endl; //7

    auto lamb3 = [&](int c) {b = a + c; };//省略返回类型,为void。
    //cout << lamb3(5) << endl; //error,返回void

    auto lamb4 = [] {return 1; }; //省略参数列表
    cout << lamb4() << endl;

    auto lamb5 = [=, &b](int c)->int {return b += a + c; }; //各部分完整的lambda表达式
    cout << "lamb5(2) = "<<lamb5(2) << ", b = " << b<< endl; //9, 9

    //2. lambda表达式的常量性及mutable关键字
    a = 1;
    //auto f1 = [] {return a++; };  //error,没有捕获外部变量
    //auto f2 = [=]() { a = 1;};    //error,const函数不能修改按值捕获的变量
    auto f2 = [=]() mutable { a = 2; }; //ok,被mutable修饰
    auto f3 = [&a]() { a = 3; };       //ok,按引用传递。const函数时影响引用本身,表示其不可修改
                                       //但其引用的内容不受const影响,仍可修改。
    //3. 捕获的时间点
    int x = 10;
    auto lambByVal = [x] {return x + 1; }; //按值捕获:声明时,x被复制一下
    auto lambByRef = [&x] {return x + 1; };//按引用捕获:x的值是随外部x的变化而变化。
    cout << "lambByVal() = "<< lambByVal() << endl; //11
    cout << "lambByRef() = "<< lambByRef() << endl; //11
    
    ++x;

    cout << "lambByVal() = " << lambByVal() << endl; //11
    cout << "lambByRef() = " << lambByRef() << endl; //12

    //4. lambda表达式转换为函数指针
    using FuncX = int(*)(int);
    using FuncXY = int(*)(int, int);

    int k = 1;
    auto lambN = [](int x, int y) {return x + y; };       //无捕获列表
    auto lambK = [&k](int x, int y) {return x + y + k; }; //有捕获列表

    FuncXY funcXY;
    funcXY = lambN; //ok,无捕获列表的lambda可转化为函数指针
    //lambN = funcXY; //error,不能将函数指针转为lambda
    //funcXY = lambK; //error,有捕获列表的lambda不能转为函数指针

    //5. 捕获this指针(见Test类)

    return 0;
}
初识lambda

相关文章:

  • 2021-06-10
  • 2021-11-04
  • 2022-12-23
  • 2022-12-23
  • 2021-09-08
  • 2021-12-02
  • 2021-11-15
猜你喜欢
  • 2021-12-12
  • 2022-12-23
  • 2021-09-08
  • 2021-06-22
  • 2021-11-22
  • 2021-04-29
  • 2022-01-23
相关资源
相似解决方案