C++开发基础——lambda表达式与std::bind闭包

C++20学习笔记——头等函数(Lambda闭包) 上述代码定义了一个函数指针,它可以储存参数为long和int、返回值为long的函数地址。但要注意的是不能将包括了fun_ptr的圆括号去掉,如果去掉该语句将被解释为返回long指针类型的函数。这样,我们就可以将fun_ptr指向任何与type_name拥有一样类型的参数与返回类型的函数了。以下写法与上述效果等效;故而很多人建议始终添加取址运算符,因为这样能够增加代码的可读性。double[ ]() {很奇怪是吧,我们同时使用了三种数学上的括号。 阅读详情

一,lambda表达式

1.基本概念

lambda表达式是从C++11开始引入的,主要用来定义匿名函数和闭包。lambda表达式可以被当作一个值赋给另一个变量,也可以作为实参传递给其他函数,或者作为其他函数的返回结果,用法类似于前面提到的函数对象和函数指针。如果只是把单个函数拿来传参,lambda表达式的使用方式比函数指针和函数对象更简洁。

lambda表达式可以不指定函数的返回类型,编译器将自动推导该类型。

lambda表达式的完整公式:

[capture_list](parameter_list) mutable -> return_type{ process code };

具体含义:

[]: lambda表达式的引出符,编译器根据该符号判断接下来的代码是否为lambda匿名函数。

parameter_list: 参数列表,与普通函数的参数列表一致。如果不需要传递参数,则可以省略该部分以及小括号()。

mutable: 使用了mutable修饰符的lambda表达式,不可以省略参数列表。

return_type: 函数返回值类型。该部分可以连同"->"一起省略。

process code: 函数体,它除了可以使用参数之外,还可以使用捕获到的变量。

lambda表达式样例:

[](int x, int y){return x<y;}        //[]用来标记lambda表达式的开始
[](int x=0, int y=0){return x<y;}    //传默认实参x=0,C++14标准开始支持
[]{return true;}                     //没有参数时,可以省略圆括号()
[](int x, int y)->bool{return x<y;}  //显式指定返回值类型,让代码更清晰

注意,lambda表达式中的"[ ]"不一定是空的,里面可以包含捕获子句,捕获子句用来捕获上下文中的变量来提供给lambda表达式使用。

C++代码样例: 

Demo1:

#include<iostream>
using namespace std;
int main() {
    auto operation = [](int a, int b, string op) -> double {
        if (op == "sum") {
            return a + b;
        }
        else {
            return (a + b) / 2.0;
        }
    };
    int num1 = 1;
    int num2 = 2;
    auto sum = operation(num1, num2, "sum");
    cout << "Sum = " << sum << endl;
    auto avg = operation(num1, num2, "avg");
    cout << "Average = " << avg;
    return 0;
}

运行结果:

Sum = 3
Average = 1.5

Demo2: lambda与std::for_each结合使用

#include <bits/stdc++.h>
#include <iostream>
using namespace std;
int main()
{
       vector<int> vec{ 1, 2, 3, 4, 5 };
       for_each(vec.begin(),
                   vec.end(),
                   [](int& a) { a *= 2; }
               );
       for_each(vec.begin(),
                   vec.end(),
                   [](int a) { cout << a << " " ; }
                );
       cout << endl;
       return 0;
}

运行结果:

2 4 6 8 10

2.关于捕获子句

捕获子句定义了lambda表达式访问(捕获)表达式以外的参数和变量的方式。

默认的捕获子句有两种即"="(按值捕获)和"&"(按引用捕获)。

为什么要有捕获子句:

当[ ]中为空时,lambda表达式只能访问lambda表达式中定义的局部实参和局部变量。当[ ]中不为空时,lambda表达式可以访问代码指定作用域中的所有参数和变量。因此,捕获子句的使用扩大了lambda表达式捕获变量的范围。

3.常见的捕获方式

方式一,按值捕获

方括号中包含"=",指定作用域中变量的值可以传递到lambda表达式,lambda表达式可以使用变量的值,但是不能修改变量的值。

方式二,按引用捕获

方括号中包含"&",指定作用域中变量的引用可以传递到lambda表达式,lambda表达式既可以使用变量的值,也可以修改变量的值。

方式三,捕获指定的变量

捕获变量和默认捕获子句的操作有些区别:

按值捕获变量:[ ]中直接传变量名,不带"="。

按引用捕获变量:[ ]中传的是 "&"后面加变量名。

捕获多个变量时可以用逗号分隔,例如:

[=, &counter]  //按引用捕获counter,按值捕获其他变量
[&, counter]    //按值捕获counter,按引用捕获其他变量

指定的默认子句("="或"&")必须是捕获列表中的第一项。

如果捕获列表的前面已经加了"="捕获子句,则后面不能再按值捕获特定变量。同理,如果捕获列表的前面已经加了"&"捕获子句,则后面不能再按引用捕获特定变量。

所以下面这两个捕获子句会产生编译错误:

[&, &counter]
[=, &counter, number]
方式四,捕获this指针

如果一个对象的成员函数中有lambda表达式,那么这个lambda表达式不能通过按值捕获或按引用捕获这个对象的成员变量。为了让lambda表达式能够访问当前对象的成员变量,应该在捕获子句中使用this关键字。

有了this指针,lambda表达式可以访问当前对象的所有成员函数和成员变量,无论它们的访问权限被声明为protected还是private。

总结下来,常见的捕获语法有:

[=]: 按值捕获所有变量。

[&]: 按引用捕获所有变量。

[=,&x,&y]: 按引用捕获变量x和y,按值捕获其他变量。

[&,x,y]: 按值捕获变量x和y,按引用捕获其他变量。

[this]: 捕获当前的对象。

[*this]: 捕获当前的对象的副本。

C++代码样例

Demo1:

#include<iostream>
using namespace std;
int main() {
    int initial_sum = 100;
    auto add_to_sum = [initial_sum](int num) {
        return initial_sum + num;
    };
    int final_sum = add_to_sum(78);
    cout << "100 + 78 = " << final_sum;
    return 0;
}

运行结果:

100 + 78 = 178

Demo2:

#include <functional>
#include <iostream>
using namespace std;
int main()
{
    int i = 3;
    int j = 5;
    function<int(void)> f1 = [i, j] { return i + j; };
    i = 22;
    j = 44;
    function<int(void)> f2 = [&i, &j] { return i + j; };
    cout << f1() << endl;
    cout << f2() << endl;
}

运行结果:

8
66

Demo3:

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Scale
{
public:
    explicit Scale(int scale) : _scale(scale) {}
    void ApplyScale(const vector<int>& v) const
    {
        for_each(v.begin(), v.end(), [this](int n) { cout << n * _scale <<" "; });
        cout << endl;
    }
private:
    int _scale;
};
int main()
{
    vector<int> values;
    values.push_back(1);
    values.push_back(2);
    values.push_back(3);
    values.push_back(4);
    Scale s(3);
    s.ApplyScale(values);
}

运行结果:

3 6 9 12

二,闭包与std::bind模板

1.什么是闭包

闭包( Closure)这个概念起源于函数式编程,是指外部变量与函数之间的绑定,可以这样理解,捕获了外部变量的lambda表达式是一种闭包。

2.std::bind的简介

std::bind是C++11标准引入的函数模板,用于取代bind1st和bind2nd等旧式语法。std::bind常用来实现闭包,它用于包装和调用特征相同的函数指针、函数对象或lambda表达式。

std::bind可以充当函数适配器,即它接受一个原函数作为输入并返回一个新的函数对象作为输出,返回的函数对象包含一个或多个与原函数绑定的参数。std::bind可以预先指定函数的所有参数,也可以将函数的部分参数预先指定好,剩下的参数等真正调用的时候再指定。

3.std::bind的用法

假如有一个计算两个数字相加的函数。

int add(int first, int second)
{
    return first + second;
}

std::bind将函数名作为其第一个参数,后面的参数用"_1,_2"这样的占位符来预留,得到一个函数对象add_func。add_func可以像函数一样直接被调用。

auto add_func = std::bind(&add, _1, _2);
add_func(4,5); //4+5, 返回9

假设遇到了特殊场景,需要将函数的第一个参数传12,第二个参数作为预留,使用方式如下。

auto new_add_func = std::bind(&add, 12, _1);
new_add_func(5); //12+5, 返回17

完整C++代码实现:

#include <iostream>
#include <functional>
using namespace std;
int add(int first, int second)
{
    return first + second;
}
int main()
{
    auto new_add_func = std::bind(&add, 12, placeholders::_1);
    int x = new_add_func(5);
    cout << x << endl;
    return 0;
}

运行结果:

17

三,参考阅读

《Beginning C++17, 5th Edition》

《深入理解C++11:C++11新特性解析与应用》

《C++高级编程》

https://leimao.github.io/blog/CPP-Closure/

https://thispointer.com/stdbind-tutorial-and-usage-details/

https://www.programiz.com/cpp-programming/lambda-expression

https://learn.microsoft.com/en-us/cpp/cpp/examples-of-lambda-expressions?view=msvc-170

C++ lambda表达式与函数对象 C++ lambda表达式与函数对象 lambda表达式是C++11中引入的一项新技术,利用lambda表达式可以编写内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读。但是从本质上来讲,lambda表达式只是一种语法糖,因为所有其能完成的工作都可以用其它稍微复杂的代码来实现。但是它简便的语法却给C++带来了深远的影响。如果从广义上说,lamdba表达式产生的是函数对象。在类中,可以... 阅读详情

相关推荐

c++ 一文彻底搞懂闭包

(3) 闭包是什么, C++和Rust的视角 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/378270921.(6) 闭包是什么, C++和Rust的视角 - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/378270921.(4) C++的闭包(closure) - 知乎 - 知乎专栏. https://zhuanlan.zhihu.com/p/121628510.闭包可以用来实现高阶函数,比如回调函数、函数式编程等¹²。

usstmiracle的博客 1458

std::bind与lambda表达式

bind-vs-lambda 参考:bind-vs-lambda 参考:why-use-stdbind-over-lambdas-in-c14 参考:Lambdas vs. std::bind in C++11 and C++14 背景介绍 In C++98, such binding was accomplished via std::bind1st and std::bind2nd. TR1 added std::tr1::bind, which was promoted to std::bind

alexhu2010q的博客 1826

C++编程进阶之std::bind与lambda表达式

(function object),这个对象内部存储了绑定的函数和参数。当调用这个函数对象时,它会将绑定的参数和传入的参数组合起来,调用原始函数。(callable object),将函数的部分参数固定下来,生成一个新的函数对象,这个新的函数对象可以在后续调用时接收剩余的参数。的本质是创建一个可调用对象,将函数的部分参数固定下来,生成一个新的函数对象。要是追求极致的性能,尤其是在性能敏感、频繁调用的代码段,功能强大,但在现代 C++ 中,lambda 表达式通常是更好的替代方案。** 占位符的作用**

1023

C++ 笔记 std::function bind 和 lambda表达式

lambda表达式 一个lambda表达式表示一个可调用的代码单元,我们可以将其理解为一个未命名的内联函数。与任何函数相似,一个lambda具有一个返回类型、一个参数列表、一个函数体。但与函数不同,lambda可以定义在函数内部,一个lambda表达式具有如下形式: [capture list捕获列表](parameter list参数列表) {函数体},例子如下: auto f = ...

flyconley的博客 921

syslog RFC5424协议详解

RFC5424协议解读与报文分析。

chenwr2018的博客 6690

Sigrity IBIS建模实战:如何用T2B工具快速转换SPICE模型(附避坑指南)

本文详细介绍了如何使用Sigrity T2B工具将SPICE模型高效转换为IBIS模型,涵盖从环境配置、模型预处理到转换流程和验证策略的全过程。通过实战案例和避坑指南,帮助硬件工程师掌握高速电路设计中的IBIS建模技术,提升信号完整性分析效率。

weixin_29243279的博客 395

std::function和std:bind

原文:http://www.jb51.net/article/104376.htm大家都知道C++11中增加了许多的新特性,下面在这篇文中我们就来聊一下lambda表达式,闭包,std::function以及std::bind。文中介绍的很详细,相信对大家具有一定的参考价值,有需要的朋友们下面来一起看看吧。前言在C++11新标准中,语言本身和标准库都增加了很多新内容,本文只涉及了一些皮毛。不过我相...

caogenwangbaoqiang的博客 434

从零到一:手把手教你用C#开发AGV调度系统(附避坑指南)

本文详细介绍了如何使用C#开发高效的AGV调度系统,涵盖从环境搭建到核心算法实现的完整流程。重点解析了动态路径规划、多机协同等关键技术,并提供了实用的避坑指南和性能优化建议,帮助开发者快速构建工业级车辆控制调度系统。

blockchain9miner的博客 742

C++ Lambda表达式默认参数限制解析与四种替代方案实践

在C++编程中,函数参数默认值是提升代码灵活性的常见手段。其原理是在函数声明时指定参数的默认值,调用时可选择性省略,从而简化接口设计,增强代码复用性。这一特性在普通函数中广泛应用,但在C++11引入的Lambda表达式中却存在语法限制——Lambda参数列表不支持直接声明默认参数。这一设计源于Lambda作为轻量级闭包的本质,其捕获机制已能实现类似“预设参数”的功能。从技术价值看,理解这一限制有助于深入掌握C++类型系统和函数对象设计哲学。在实际工程中,开发者常通过捕获列表、高阶函数工厂、std::bind

weixin_30984001的博客 306

Camera(5)metadata

Metadata 是整个 Android camera 中类似于高楼大厦中的管道系统一样,贯穿了整个 Camera 的 Framework 和 vendor HAL。Metadata 里面包含了所有的控制、参数、返回值等等。Metadata分为Android原生的Metadata和芯片商或者用户自定义的Metadata,即Android Tag和Vendor Tag。Vendor Tag在Hal中定义,并在camx和chi目录中使用。

qq_55893245的博客 3052

PS/Ai/PR/AE等adobe出现正版弹窗提示:Your non-genuine Adobe app will be disabled soon解决办法

就是用专门的清理工具下载,清理工具在文章下方。然后新建三个空的记事本文件,重命名为 Adobe Genuine Launcher.exe,AdobeGCClient.exe,AGMService.exe。在该文件目录中,分别找到 Adobe Genuine Launcher.exe,AdobeGCClient.exe,AGMService.exe,然后在防火墙入站规则里,阻止Adobe Genuine Launcher.exe,AdobeGCClient.exe,AGMService.exe。

Q82556499的博客 1万+

举例:用std::bind来实现闭包

std::bind可以充当函数适配器,即它接受一个原函数作为输入并返回一个新的函数对象作为输出,返回的函数对象包含一个或多个与原函数绑定的参数。std::bind可以预先指定函数的所有参数,也可以将函数的部分参数预先指定好,剩下的参数等真正调用的时候再指定。闭包( Closure)这个概念起源于函数式编程,是指外部变量与函数之间的绑定,可以这样理解,捕获了外部变量的lambda表达式是一种闭包。std::bind是C++11标准引入的函数模板,用于取代bind1st和bind2nd等旧式语法。

tumu_C的博客 250

CoMP 协同多点传输技术

CoMP CoMP是什么 解决什么问题 有什么缺点 CoMP(Coordinated Multiple Points)协同多点传输,通信术语,LTE-A的重要技术之一。 CoMP传输是指地理位置上分离的多个传输点,协同参与为一个终端的数据(PDSCH)传输或者联合接收一个终端发送的数据(PUSCH),参与协作的多个传输点通常指不同小区的基站。CoMP技术将边缘用户置于几个基站的同频率上,几...

ilean_J的博客 2万+

【C++11】闭包:仿函数operator() && 绑定器bind && 包装器function && lambda表达式

​闭包有很多种定义, 一种说法是, 闭包是带有上下文的函数。说白了, 就是有状态的函数,就是有自己的变量。更直接一些,就是一个类换了个名字而已。​一个函数, 带上了一个状态, 就变成了闭包了。那什么叫“带上状态”呢?意思是这个闭包有属于自己的变量, 这些个变量的值是创建闭包的时候设置的, 并在调用闭包的时候, 可以访问这些变量。​函数是代码, 状态是一组变量, 将代码和一组变量捆绑 (bind) , 就形成了闭包。闭包的状态捆绑, 必须发生在运行时。

lirendada的博客 1501

双目摄像头全景解析:从几何光学到深度智能

双目视觉系统基于仿生学原理,通过水平排列的双摄像头模拟人眼视差机制实现三维感知。其核心是通过标定、校正、匹配等算法流程,将视差转换为深度信息,最终生成三维点云。该系统在自动驾驶、机器人导航、工业检测等领域有广泛应用,但面临弱纹理、重复图案等挑战。未来发展趋势包括与事件相机、深度学习等技术的融合,进一步提升精度和动态性能。

reset2021的博客 120

qiankun 主子应用部署教程(Nginx 小白版)

本地开发:不用 Nginx,直接localhost:端口即可。本地模拟线上:用hosts + Nginx + 自定义域名,效果和生产接近。线上部署主应用只要配置 history 模式子应用必须支持 CORS + history + 缓存能跑是因为默认 server 兜底,但推荐写真实域名。主应用 vs 子应用的 Nginx 配置区别为什么本地和线上表现不一样history 模式 + 跨域的最佳实践。

专注于前端开发与实战技巧,记录从零到一的学习与项目经验。分享 Vue3 / JavaScript / TypeScript / Flutter /Uniapp等前端技术,以及 性能优化、工程化、最佳实践。 999

C++11:std::function<void()> func;

转自:使用std::function作为函数入参 关于std::function() 在C语言的时代,我们可以使用函数指针来吧一个函数作为参数传递,这样我们就可以实现回调函数的机制。到了C++11以后在标准库里引入了std::function模板类,这个模板概括了函数指针的概念 函数指针只能指向一个函数,而std::function对象可以代表任何可以调用的对象,比如说任何可以被当作函数一样调用的对象。 当你创建一个函数指针的时候,你必须定义这个函数签名(表征这个函数的入参,返回值等信息);同样的,当你创建

苦逼的程序猿☺ 1万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++ :std::bind 还能用吗?它和 Lambda 有什么区别?

本文探讨了现代C++中std::bind与Lambda表达式的地位对比。虽然std::bind在C++11之前是参数绑定的主要工具,但随着Lambda的出现,其可读性差、调试困难等缺点逐渐显现。尽管标准未废弃std::bind,但现代C++更推荐使用Lambda,因其语法直观、捕获机制灵活、调试友好。std::bind在特定场景仍有价值,如兼容旧接口、函数式编程或模板代码中,但整体上已被Lambda取代。建议在普通业务逻辑中优先使用Lambda,仅在必要时考虑std::bind。

htw250056的博客 1047

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

《C++进阶之C++11》【lambda表达式 + 包装器】

本文介绍了C++中的lambda表达式和函数包装器的核心概念与用法。重点讲解了捕获列表的三种方式。文章通过代码示例详细演示了lambda的各种捕获方式和用法特点,适合C++进阶学习。

序属秋秋秋的博客 1659

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

详解c++中的可调用对象,std::function、Lambda表达式、std::bind等

可调用对象用处广泛,比如在使用一些基于范围的模板函数时(如 sort()、all_of()、find_if() 等),常常需要我们传入一个可调用对象,以指明我们需要对范围中的每个元素进行怎样的处理。又比如,在处理一些回调函数、触发函数时,也常常会使用可调用对象。()等。上面演示了最简单的可调用对象。

z3363的博客 1206

C++ 中 function、bind、lambda 详解:可调用对象的三剑客

Lambda 表达式是 C++11 引入的语法糖,用于在代码中就地定义匿名函数对象。它是编译器生成的、具有唯一类型的闭包对象。cpp复制下载// lambda 语法:[捕获列表](参数列表) -> 返回类型 { 函数体 }// 大多数情况可省略返回类型// 各种捕获方式// [=] : 按值捕获所有外部变量// [&] : 按引用捕获所有外部变量b++;c++;// 混合捕获// 初始化捕获(C++14):捕获表达式结果。

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 1184

C++编程中Lambda表达式与std::bind的对比与选择

在C++编程中,函数对象和回调机制是实现灵活代码设计的基础概念。其核心原理是通过封装可调用单元,将行为参数化,从而提升代码的模块化和复用性。从技术价值看,现代C++强调零开销抽象和编译期优化,这直接影响了函数封装技术的选择。Lambda表达式作为C++11引入的语法糖,本质是编译器生成的匿名函数对象,其闭包类型对编译器完全可见,支持内联优化,实现了接近手写代码的性能。相比之下,std::bind作为通用的运行时绑定器,涉及类型擦除和参数转发,会引入额外的间接调用开销。在应用场景上,无论是STL算法中的谓词、

weixin_33906657的博客 313

C++ 新特性详解:std::bind 函数绑定

今天我们来学习std::bind

筏的博客 2288

C++Lambda 表达式与函数对象

C++Lambda表达式、std::binding、std::function、std::packaged_task语法讲解

2401_82413779的博客 929

【转载】想看懂WebRtc,你须知道的C++11新特性「lambda,std::function以及std:bind」

转载自https://cloud.tencent.com/developer/article/1608796 C++11 中增加了许多的新特性。 在本文中,我们来聊一下 lambda 表达式,闭包,std::function以及std::bind。 lambda 表达式 C++11 中新增了 lambda 表达式这一语言特性。lambda 表达式可以让我们快速和便捷的创建一个 “函数”。 下面是lambda表达式的语法: [ capture-list ] { body } [ capture.

ShaderJoy 的兴趣技术杂货铺 1416
上一篇: C++开发基础——指针与引用
下一篇: C++设计模式——Adapter适配器模式
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员与背包客_CoderZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值