lambda表达式

lambda 表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。lambda 表达式的语法形式可简单归纳如下:

[ capture ] ( params ) opt -> ret { body; };

其中 capture 是捕获列表,params 是参数表,opt 是函数选项,ret 是返回值类型,body是函数体。
因此,一个完整的 lambda 表达式看起来像这样:

auto f = [](int a) -> int { return a + 1; };
std::cout << f(1) << std::endl; // 输出: 2

其实很多时候,lambda 表达式的返回值是非常明显的,比如这个例子。因此,C++11 中允许省略 lambda 表达式的返回值定义:

需要注意的是,初始化列表不能用于返回值的自动推导:

auto x1 = [](int i){ return i; };  // OK: return type is int
auto x2 = [](){ return { 1, 2 }; };  // error: 无法推导出返回值类型

这时我们需要显式给出具体的返回值类型。
另外,lambda 表达式在没有参数列表时,参数列表是可以省略的。因此像下面的写法都是正确的:

auto f1 = [](){ return 1; };
auto f2 = []{ return 1; };  // 省略空参数表

lambda 表达式还可以通过捕获列表捕获一定范围内的变量:

  • [] 不捕获任何变量。
  • [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
  • [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
  • [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
  • [bar] 按值捕获 bar 变量,同时不捕获其他变量。
  • [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。

    复制代码
    class A
    {
        public:
        int i_ = 0;
        void func(int x, int y)
        {
            auto x1 = []{ return i_; };                    // error,没有捕获外部变量
            auto x2 = [=]{ return i_ + x + y; };           // OK,捕获所有外部变量
            auto x3 = [&]{ return i_ + x + y; };           // OK,捕获所有外部变量
            auto x4 = [this]{ return i_; };                // OK,捕获this指针
            auto x5 = [this]{ return i_ + x + y; };        // error,没有捕获x、y
            auto x6 = [this, x, y]{ return i_ + x + y; };  // OK,捕获this指针、x、y
            auto x7 = [this]{ return i_++; };              // OK,捕获this指针,并修改成员的值
        }
    };
    int a = 0, b = 1;
    auto f1 = []{ return a; };               // error,没有捕获外部变量
    auto f2 = [&]{ return a++; };            // OK,捕获所有外部变量,并对a执行自加运算
    auto f3 = [=]{ return a; };              // OK,捕获所有外部变量,并返回a
    auto f4 = [=]{ return a++; };            // error,a是以复制方式捕获的,无法修改
    auto f5 = [a]{ return a + b; };          // error,没有捕获变量b
    auto f6 = [a, &b]{ return a + (b++); };  // OK,捕获a和b的引用,并对b做自加运算
    auto f7 = [=, &b]{ return a + (b++); };  // OK,捕获所有外部变量和b的引用,并对b做自加运算
    复制代码

     在这个例子中,lambda 表达式按值捕获了所有外部变量。在捕获的一瞬间,a 的值就已经被复制到f中了。之后 a 被修改,但此时 f 中存储的 a 仍然还是捕获时的值,因此,最终输出结果是 0。

    如果希望 lambda 表达式在调用时能够即时访问外部变量,我们应当使用引用方式捕获。

    从上面的例子中我们知道,按值捕获得到的外部变量值是在 lambda 表达式定义时的值。此时所有外部变量均被复制了一份存储在 lambda 表达式变量中。此时虽然修改 lambda 表达式中的这些外部变量并不会真正影响到外部,我们却仍然无法修改它们。

  • int a = 0;
    auto f1 = [=]{ return a++; };             // error,修改按值捕获的外部变量
    auto f2 = [=]() mutable { return a++; };  // OK,mutable

     

posted @   LuisLee  阅读(122)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示