广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++lambda函数详解
  • 161
分享到

C++lambda函数详解

C++lambda表达式C++lambda函数 2023-02-13 18:02:39 161人浏览 泡泡鱼
摘要

目录Lambda 表达式基础1. 值捕获2. 引用捕获3. 隐式捕获4. 表达式捕获泛型 Lambda函数对象包装器Lambda 表达式 Lambda 表达式是现代 c++ 中最重要

Lambda 表达式

Lambda 表达式是现代 c++ 中最重要的特性之一,而 Lambda 表达式,实际上就是提供了一个类似匿名函数的特性, 而匿名函数则是在需要一个函数,但是又不想费力去命名一个函数的情况下去使用的。这样的场景其实有很多很多, 所以匿名函数几乎是现代编程语言的标配。

基础

Lambda 表达式的基本语法如下:

[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {
// 函数体
}

上面的语法规则除了 [捕获列表] 内的东西外,其他部分都很好理解,只是一般函数的函数名被略去, 返回值使用了一个 -> 的形式进行(我们在上一节前面的尾返回类型已经提到过这种写法了)。

所谓捕获列表,其实可以理解为参数的一种类型,Lambda 表达式内部函数体在默认情况下是不能够使用函数体外部的变量的, 这时候捕获列表可以起到传递外部数据的作用。根据传递的行为,捕获列表也分为以下几种:

1. 值捕获

与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在 Lambda 表达式被创建时拷贝, 而非调用时才拷贝:

void lambda_value_capture() {
    int value = 1;
    auto copy_value = [value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 1, 而 value == 100.
    // 因为 copy_value 在创建时就保存了一份 value 的拷贝
}

2. 引用捕获

与引用传参类似,引用捕获保存的是引用,值会发生变化。

void lambda_reference_capture() {
    int value = 1;
    auto copy_value = [&value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 100, value == 100.
    // 因为 copy_value 保存的是引用
}

3. 隐式捕获

手动书写捕获列表有时候是非常复杂的,这种机械性的工作可以交给编译器来处理,这时候可以在捕获列表中写一个 & 或 = 向编译器声明采用引用捕获或者值捕获.

总结一下,捕获提供了 Lambda 表达式对外部值进行使用的功能,捕获列表的最常用的四种形式可以是:

a. [] 空捕获列表
b. [name1, name2, ...] 捕获一系列变量
c. [&] 引用捕获, 让编译器自行推导引用列表
d. [=] 值捕获, 让编译器自行推导值捕获列表

4. 表达式捕获

这部分内容需要了解后面马上要提到的右值引用以及智能指针

上面提到的值捕获、引用捕获都是已经在外层作用域声明的变量,因此这些捕获方式捕获的均为左值,而不能捕获右值。

C++14 给与了我们方便,允许捕获的成员用任意的表达式进行初始化,这就允许了右值的捕获, 被声明的捕获变量类型会根据表达式进行判断,判断方式与使用 auto 本质上是相同的:

#include <iOStream>
#include <memory>  // std::make_unique
#include <utility> // std::move
void lambda_expression_capture() {
    auto important = std::make_unique<int>(1);
    auto add = [v1 = 1, v2 = std::move(important)](int x, int y) -> int {
        return x+y+v1+(*v2);
    };
    std::cout << add(3,4) << std::endl;
}

在上面的代码中,important 是一个独占指针,是不能够被 "=" 值捕获到,这时候我们可以将其转移为右值,在表达式中初始化。

泛型 Lambda

上一节中我们提到了 auto 关键字不能够用在参数表里,这是因为这样的写法会与模板的功能产生冲突。 但是 Lambda 表达式并不是普通函数,所以在没有明确指明参数表类型的情况下,Lambda 表达式并不能够模板化。 幸运的是,这种麻烦只存在于 C++11 中,从 C++14 开始,Lambda 函数的形式参数可以使用 auto 关键字来产生意义上的泛型:

auto add = [](auto x, auto y) {
    return x+y;
};
add(1, 2);
add(1.1, 2.2);

函数对象包装器

这部分内容虽然属于标准库的一部分,但是从本质上来看,它却增强了 C++ 语言运行时的能力, 这部分内容也相当重要,所以放到这里来进行介绍。

std::function

Lambda 表达式的本质是一个和函数对象类型相似的类类型(称为闭包类型)的对象(称为闭包对象), 当 Lambda 表达式的捕获列表为空时,闭包对象还能够转换为函数指针值进行传递,例如:

#include <iostream>
using foo = void(int); // 定义函数类型, using 的使用见上一节中的别名语法
void functional(foo f) { // 参数列表中定义的函数类型 foo 被视为退化后的函数指针类型 foo*
    f(1); // 通过函数指针调用函数
}
int main() {
    auto f = [](int value) {
        std::cout << value << std::endl;
    };
    functional(f); // 传递闭包对象,隐式转换为 foo* 类型的函数指针值
    f(1); // lambda 表达式调用
    return 0;
}

上面的代码给出了两种不同的调用形式,一种是将 Lambda 作为函数类型传递进行调用, 而另一种则是直接调用 Lambda 表达式,在 C++11 中,统一了这些概念,将能够被调用的对象的类型, 统一称之为可调用类型。而这种类型,便是通过 std::function 引入的。

C++11 std::function 是一种通用、多态的函数封装, 它的实例可以对任何可以调用的目标实体进行存储、复制和调用操作, 它也是对 C++ 中现有的可调用实体的一种类型安全的包裹(相对来说,函数指针的调用不是类型安全的), 换句话说,就是函数的容器。当我们有了函数的容器之后便能够更加方便的将函数、函数指针作为对象进行处理。 例如:

#include <functional>
#include <iostream>
int foo(int para) {
    return para;
}
int main() {
    // std::function 包装了一个返回值为 int, 参数为 int 的函数
    std::function<int(int)> func = foo;
    int important = 10;
    std::function<int(int)> func2 = [&](int value) -> int {
        return 1+value+important;
    };
    std::cout << func(10) << std::endl;
    std::cout << func2(10) << std::endl;
}
std::bind 和 std::placeholder

而 std::bind 则是用来绑定函数调用的参数的, 它解决的需求是我们有时候可能并不一定能够一次性获得调用某个函数的全部参数,通过这个函数, 我们可以将部分调用参数提前绑定到函数身上成为一个新的对象,然后在参数齐全后,完成调用。 例如:

int foo(int a, int b, int c) {
    ;
}
int main() {
    // 将参数1,2绑定到函数 foo 上,
    // 但使用 std::placeholders::_1 来对第一个参数进行占位
    auto bindFoo = std::bind(foo, std::placeholders::_1, 1,2);
    // 这时调用 bindFoo 时,只需要提供第一个参数即可
    bindFoo(1);
}

提示:注意 auto 关键字的妙用。有时候我们可能不太熟悉一个函数的返回值类型, 但是我们却可以通过 auto 的使用来规避这一问题的出现。

到此这篇关于C++ lambda函数详解的文章就介绍到这了,更多相关C++ lambda内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: C++lambda函数详解

本文链接: https://www.lsjlt.com/news/195862.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++lambda函数详解
    目录Lambda 表达式基础1. 值捕获2. 引用捕获3. 隐式捕获4. 表达式捕获泛型 Lambda函数对象包装器Lambda 表达式 Lambda 表达式是现代 C++ 中最重要...
    99+
    2023-02-13
    C++ lambda表达式 C++ lambda函数
  • C++中的Lambda函数详解
    目录一 函数语法二 函数应用1、在普通函数中使用2、在qt信号槽中使用3、在std::sort排序函数中的使用三 总结一 函数语法 我们平时调用函数的时候,都是需要被调用函数的函数名...
    99+
    2022-11-12
  • C++匿名函数lambda详解
    匿名函数lambda 一、匿名函数的基本语法二、捕获列表2.1、值捕获2.2、引用捕获2.3、隐式捕获2.4、空捕获列表2.5、表达式捕获2.6、泛型 Lambda2.7、可变lambda2....
    99+
    2023-10-23
    c++ linux 开发语言 服务器 算法
  • 一文详解C++11中的lambda函数
    目录1.lambda函数语法1.1 捕获列表1.2 mutable修饰符1.3 匿名lambda函数2.lambda与STL我可以明确告诉你:lambda函数是C++11中最重要的,...
    99+
    2023-02-07
    C++11 lambda函数使用 C++11 lambda函数 C++11 lambda
  • C++11中匿名函数lambda的使用详解
    目录一、lambda基础介绍二、lambda使用例子2.1 STL算法中的回调函数2.2 回调函数2.3 多线程编程三、总结官方介绍: C++ lambda是C++11新增的一种匿名...
    99+
    2023-05-18
    C++11匿名函数lambda使用 C++11匿名函数lambda C++11匿名函数
  • python函数和python匿名函数lambda详解
    目录1. python函数1.1 函数的作用1.2 函数定义1.3 函数调用1.4 函数的参数1.4.1 参数的传递1.4.2 参数类型1.4.2.1 位置参数(必备参数)1.4.2...
    99+
    2022-11-11
  • 详解Python的lambda函数用法
    lambda函数用法 lambda非常重要的一个定义。lambda在【运行时】才绑定,【不是】在定义的时候绑定。下面这个列子: 本意想:让X分别与0到1的数相加。x+0,x+1,x+2,x+3 实际运行结果是: 0...
    99+
    2022-06-02
    lambda函数用法 Python lambda Python函数
  • python中lambda匿名函数详解
    在Python中,不通过def来声明函数名字,而是通过lambda关键字来定义的函数称为匿名函数 关键字lambda表示匿名函数 语法 lambda 参数:表达式 先写lambda关...
    99+
    2022-11-13
  • 详解Python的Lambda函数与排序
    lambda函数是一种快速定义单行的最小函数,是从 Lisp 借用来的,可以用在任何需要函数的地方。下面的例子比较了传统的函数与lambda函数的定义方式。 前几天看到了一行求1000的阶乘的Python...
    99+
    2022-06-04
    详解 函数 Python
  • python3中apply函数和lambda函数的使用详解
    目录lambda函数lambda是什么lambda用法详解lambda + maplambda + filterlambda + reduce避免过度使用lamb...
    99+
    2022-11-13
  • C++Lambda表达式详解
    目录概述语法分析捕获列表关键字声明示例捕获列表按值传递总结概述 C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。Lambda 的语法形式如下: ...
    99+
    2022-11-12
  • C++ lambda函数怎么使用
    本篇内容介绍了“C++ lambda函数怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Lambda 表达式Lambda 表...
    99+
    2023-07-05
  • C++11 lambda(匿名函数)表达式详细介绍
    目录前言概念及基本用法捕获变量lambda表达式类型声明式的编程风格总结前言 Lambda(匿名函数)表达式是C++11最重要的特性之一,lambda来源于函数式编程的概念,也是现代...
    99+
    2022-11-13
  • C# 本地函数与 Lambda 表达式详细介绍
    目录1、C# 本地函数与 Lambda 表达式2、Lambda 表达式3、本地函数4、那么,局部函数的目的是什么?1、C# 本地函数与 Lambda 表达式 C# 局部函数通常被视为...
    99+
    2022-11-12
  • C++ 内联函数详解
    目录一、C++ 内联函数1.内联2.语法3.评价总结一、C++ 内联函数 1.内联 C 语言中有宏函数的概念。宏函数的特点是内嵌到调用代码中去,避免了函数调用的开销。但是由于宏函数的...
    99+
    2022-11-12
  • 详解C++构造函数
    目录1.作用2.代码举例2.1 示例1:2.2 示例2:3. 使用3.1 使用构造函数初始化3.2 有参数的构造函数3.3 默认的构造函数4. 成员初始化列表例1:正常初始化例2:成...
    99+
    2022-11-12
  • C++ 纯虚函数详解
    目录虚函数 纯虚函数总结虚函数  在基类中将一个函数声明为虚函数,使该函数具有虚属性,那么其所有派生函数中该函数的重写都具备了虚属性,也就使得基类指针可以调用派生...
    99+
    2022-11-12
  • C++函数指针详解
    函数指针基础: 1. 获取函数的地址 2. 声明一个函数指针 3.使用函数指针来调用函数 获取函数指针: 函...
    99+
    2022-11-12
  • C#构造函数详解
    一、简介 构造函数,基本用法是在类对象声明的时候完成初始化工作。 二、实例构造函数 1、构造函数的名字与类名相同。 2、使用 new 表达式创建类的对象或者结构(例如int)时,会调...
    99+
    2022-11-13
  • C++构造函数详解
    文章转自公众号:Coder梁(ID:Coder_LT) 上一篇文章我们介绍了定义了类,在使用之前,往往还需要对类进行初始化。这篇介绍的就是对类进行初始化的方法。 像是结构体,我们可以...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作