C++ Lambda表达式

C++ Lambda表达式

参考链接:

匿名函数

没有和标识符绑定的函数定义叫做匿名函数(anonymous function),也可以叫做Lambda表达式(lambda expression)。匿名函数一般会用作高阶函数的参数,或者在需要返回一个函数的场景下使用。

如果有个函数只需要用一次或者几次,那么采用匿名函数会比使用具名函数更加简便。

参考链接:

匿名函数抽象出一种运算,比如,想给数组中的每个元素加1,可以这样写:

#include <vector>

int main() {
    std::vector<int> a = {1, 2, 3, 4, 5};
    for (auto &i : a) i = i + 1;
}

但是写成下面这样会更清楚地看出,语句是对数组中的每个元素做了一个“加1”的操作;

#include <vector>
#include <algorithm>

int main() {
    std::vector<int> a = {1, 2, 3, 4, 5};
    std::for_each(a.begin(), a.end(), [](auto & x){ x = x + 1; }); 
}

参考链接:

函数对象

函数对象,有时也被称作仿函数(functor),顾名思义,就是一个使用起来像函数,但其实并不是函数的东西。它是通过重载类的()运算符来实现的这种效果。

#include <iostream>

struct add_n {
    int num;
    add_n(int _n) : num(_n) {}
    int operator()(int val) const { return num + val; }
};

int main() {
    add_n add_16(16);
    std::cout << add_16(16); // 输出32
}

上面的代码片中重载了add_n类的operator()方法,也就是()运算符,然后声明了一个add_n类的实例add_16,接着调用了实例的operator()方法,看起来就像是使用了一个名为add_16的函数。

参考链接:

闭包

闭包可以理解成一保存着函数及其运行环境/状态的包。像上文的add_n(的实例)就可以看成是一个闭包。

使用Lambda表达式

先来看C++中Lambda表达式的几种形式,其中captures是表示需要捕获的变量,也就是匿名函数中需要用到的变量,params是需要接收的参数,ret是返回值类型,body则是函数体

原型说明
[ captures ] ( params ) -> ret { body }Lambda表达式的原型
[ captures ] ( params ) { body }返回值可以自动推导,所以可以不用指明返回值
[ captures ] { body }如果函数不要参数,那么参数也可以省略掉

先从比较简单的几个例子说起:

#include <iostream>
int main() {
    auto hello = []{ std::cout << "Hello"; }; // 定义
    hello(); // 调用,输出"Hello"
    
    auto add = [](int a, int b) -> int { return a + b; }; // 指明返回类型
    auto multiply = [](int a, int b) { return a * b; };
    std::cout << "2 + 3 = " << add(2, 3);
    std::cout << "2 * 3 = " << multiply(2,3);
}

比如使用标准库的排序的时候也可以用到匿名函数:

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

int main() {
    using item_id_pair = std::pair<std::string, int>;
    std::vector<item_id_pair> items = {
        {"Melon", 5}, {"Apple", 1}, {"Cherry", 3}
    };
    auto sortByID = [](const item_id_pair & a, const item_id_pair & b){
        return a.second < b.second;
    };
    std::sort(items.begin(), items.end(), sortByID);
    for (auto i : items) {
        std::cout << "ID: " << i.second << "\t" << i.first << '\n';
    }
}

那么[]有什么用呢(不是为了好看),联系之前提到的的“闭包”,其实[]是用来捕获(capture)作用域中的变量的。捕获的变量就会被封装进这个“包”里面。捕获可以是值传递的方式,也可以是引用。

[]中写变量名时,该变量就会被以值传递的方式捕捉进闭包类中,这种情况下无法修改捕捉到的值。如果想要改动值传递捕获的值,需要使用mutable关键字。

#include <iostream>
int main() {
    int x = 10;
    // auto foo = [x](int a) { x += a; return x; }; // error!
    auto foo = [x](int a) mutable { 
        x += a; 
        return x; 
    };
    std::cout << foo(2) << '\n';  // 输出 12
    std::cout << foo(3) << '\n';  // 输出 15
    std::cout << x;               // 输出 10
}

在变量名前加&则为引用捕获:

#include <iostream>
int main() {
    int x = 10;
    auto foo = [&x](int a) { x += a; return x; };
    std::cout << foo(2) << '\n';  // 输出 12
    std::cout << foo(3) << '\n';  // 输出 15
    std::cout << x;               // 输出 15
}

[]中写=表示默认以值捕获所有变量,写&表示默认以引用捕获所有变量,如果有例外情况写在后面就好,以逗号,分割,如:

  • [=, &x]:默认以值捕获所有变量,但是x是例外,通过引用捕获;
  • [&, x]:默认以引用捕获所有变量,但是x是例外,通过值捕获;

引用捕获不会延长变量生存期,因此有可能出现“悬挂引用(Dangling references)”,比如这样:

auto make_function(int x) {
    return [&](int a) { return x + a; };
}

int main() {
    auto foo = make_function(5);
    foo(3);
}

在调用函数foo的时候,因为临时变量x已经被销毁,所以会返回奇奇怪怪的结果。


讲到这里,本篇文章就不深入讨论了,未尽事宜请阅读前文给出的链接,或自行查阅资料。

参考链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++ Lambda表达式是一种简洁的匿名表示方法,可以在代码中定义并使用。Lambda表达式的格式一般为:[] (参数列表) mutable -> 返回值类型 { 表达式 }。Lambda表达式可以捕获外部变量,并将其作为参数传递给函数体部分进行处理。Lambda表达式在使用时可以作为函数对象、函数指针或者函数参数进行传递。 Lambda表达式的底层原理是通过生成一个匿名类来实现。该类会重载函数调用运算符(),并包含Lambda表达式的函数体。Lambda表达式中捕获的外部变量会以成员变量的形式存储在该类中。当Lambda表达式被调用时,实际上是调用了该类的重载函数调用运算符()。 Lambda表达式可以与std::function结合使用,以实现函数对象的灵活使用。也可以将Lambda表达式赋值给相同类型的函数指针,实现函数指针的使用。但一般不建议这样使用,因为Lambda表达式已经提供了更加方便和简洁的方式。 总结来说,C++ Lambda表达式是一种用于定义匿名函数的语法,可以捕获外部变量并进行处理。其底层通过生成一个匿名类来实现,并提供了与std::function和函数指针的结合使用方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++11:lambda表达式](https://blog.csdn.net/zhang_si_hang/article/details/127117260)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值