五、Lambda表达式

Lambda表达式是一种用于定义匿名函数对象的便捷语法,自C++11引入后极大简化了代码编写,尤其是在需要传递短小函数逻辑的场景(如STL算法、回调函数等)

基本语法

[捕获列表] (参数列表) -> 返回类型 
{ 
    函数体 
}

//eg
aotu add = [](int a, int b) -> int 
{
	return a + b;
}

cout << add(3, 4) << endl;

捕获列表(Capture List)

定义了Lambda表达式可以访问的外部变量及其访问方式(值捕获或引用捕获)

  • []:不捕获任何外部变量
  • [x]:按值捕获变量x
  • [&x]:按引用捕获变量x
  • [=]:按值捕获所有外部作用域的变量
  • [&]:按引用捕获所有外部作用域的变量
  • [=, &x]:按值捕获所有外部变量,但是按引用捕获变量x
  • [&, x]:按引用捕获所有外部变量,但是按值捕获变量x
  • [this]:捕获Lambda表达式所在的成员函数所属对象的指针

参数列表(parameters)

与普通函数的参数列表相同

可以为空

返回类型(return_type)

在大多数情况下,返回类型可以被省略,编译器会根据函数体中的返回语句自动推断返回类型

函数体(function body)

包含了Lambda函数的实现;
除了可以使用参数之外,还可以使用捕获变量

#include <iostream>

using namespace std;

int main(int argc, const char *argv[])
{
    //不捕获任何外部变量[]
    auto printHello = []()
    {
        cout << "[]--->" << "hello world" << endl;
    };
    printHello();//"hello world"

    //按值捕获[x]
    int x = 10;
    auto add = [x](int a)
    {
        return a + x;
    };
    cout << "[x]-->" << add(5) << endl;//15

    //按引用捕获[&x]
    x = 10;
    auto setX = [&x]()
    {
        x = 20;
    };
    setX();
    cout << "[&x]-->" << x << endl;//20
  
    //按值捕获所有外部变量[=]
    x = 10;
    int y = 20;
    auto sum = [=]()
    {
        return x + y;
    };
    cout << "[=]-->" << sum() << endl;//30

    //按引用捕获所有外部变量[&]
    x = 10;
    y = 20;
    auto setXY = [&]()
    {
        x = 100;
        y = 200;
    };
    setXY();
    cout << "[&]-->" << x << " " << y << endl;//100 200

    //按值捕获所有外部变量,但按引用捕获特定的变量[=, &x]
    x = 10;
    y = 20;
    auto setXAndSum = [=, &x]()
    {
        x *= 2;
        return x + y;
    };
    cout << "[=, &x]-->" << setXAndSum() << " " << "x = " << x << endl;//40 20

    //按引用捕获所有外部变量,但按值捕获特定的变量[&, x]
    x = 10;
    y = 20;
    auto setYAndSum = [&, x]()
    {
        y *= 2;
        return x + y;
    };
    cout << "[&, x]-->" << setYAndSum() << " " << "y = " << y << endl;//50 40

    return 0;
}

注意事项

  1. 如果使用值捕获,lambda表达式的一个特性:捕获的变量默认为常量,或者说lambda是一个常量函数

    需要在函数体中修改变量值,需要加上说明符mutable,还多了一对()
    语法规定lambda表达式如果存在说明符,那么形参列表不能省略

    mutable说明符是为了突破const的限制而设置

    被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中

    #include <iostream>
    
    using namespace std;
    
    int main(int argc, const char *argv[])
    {
        //按值捕获[x]
        int x = 10;
        auto add = [x] (int a) mutable
        {
            x = 100;
            return a + x;
        };
        cout << "[x]-->" << add(5) << endl;//105
    
        return 0;
    }
    
    
  2. Lambda表达式默认是const的,即它们不能修改捕获的变量的值,除非你明确指定捕获的变量为非const

  3. 使用Lambda表达式时,应注意其生命周期,特别是当按引用捕获外部变量时,必须确保被引用的变量在Lambda被调用时仍然有效

    避免捕获局部变量的引用后超出其作用域(悬垂引用)

    按值捕获的变量在Lambda创建时拷贝,后续外部变量修改不影响Lambda内的副本

  4. 性能优化:Lambda通常被编译器内联,性能接近手写代码;

    避免在频繁调用的路径中捕获大型对象(按值捕获可能带来拷贝开销)

  5. 与std::function关系

    Lambda可隐式转换为 std::function,但可能引入类型擦除开销

    直接使用auto存储lambda可保留类型信息,效率更高

底层实现

  1. Lambda表达式是通过生成一个匿名类(或称为闭包类型)的实例来实现的
  2. 这个匿名类内部重载了函数调用操作符operator() ,使得这个类的实例可以像函数一样被调用
  3. 每当定义一个Lambda表达式时,编译器会根据Lambda表达式的定义自动生成这样一个匿名类,并实例化一个该匿名类的对象

这个过程完全在编译时完成,不会导致运行时开销

// Lambda表达式
auto lambda = [x](int a) { return x + a; };

// 编译器生成的等效类
class __AnonymousLambda {
private:
    int x; // 按值捕获的变量
public:
    __AnonymousLambda(int x) : x(x) {}
    int operator()(int a) const { 
        return x + a; 
    }
};

//编译器将lambda变量实例化为这个匿名类的对象
__AnonymousLambda lambda(x);

常用用法

与STL算法结合

std::vector<int> nums = {1, 2, 3, 4};
// 使用Lambda过滤偶数
auto it = std::remove_if(nums.begin(), nums.end(), 
    [](int n) { return n % 2 != 0; });
nums.erase(it, nums.end());

作为回调函数

//函数
//callback = [](int result)
void processDate(std::function<void(int)> callback)
{
	cout << "processDate" << endl;
	callback(42);//调用lambda的函数体
}

//调用processDate函数,传入Lambda表达式
processDate([](int result)
{
	cout << "Result" << result;
}

Lambda高级特性

可变lambda(mutable关键字)

默认Lambda的 operator()const 的,使用 mutable 允许修改按值捕获的变量:

int counter = 0;
auto increment = [counter]() mutable {
    counter++;
    std::cout << counter; 
};
increment(); // 输出 1
increment(); // 输出 2(修改的是副本)

捕获表达式(C++14)

std::unique_ptr<int> ptr = std::make_unique<int>(42);
auto lambda = [p = std::move(ptr)]() { 
    std::cout << *p; // p 是移动后的 unique_ptr
};

模板lambda(C++20)

auto print = []<typename T>(T value) {
    std::cout << value;
};
print(10);       // T 推导为 int
print(3.14);     // T 推导为 double
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值