lambda和bind详解

神州数码OSPF实战配置详解(手把手教学) 本文提供神州数码设备上OSPF基础配置的详细实战教程。通过搭建典型的两台三层交换机互联实验环境,手把手演示了VLAN创建、接口IP配置、OSPF进程启动、Router-ID设置及网络宣告等核心步骤,并分享了邻居状态验证、路由检查及常见排错方法,帮助网络工程师快速掌握神州数码OSPF的配置要点与操作技巧。 阅读详情

精华:

什么是可调用对象

就是可以对它使用调用运算符()的对象或者表达式

在c++ 中有以下几种可调用的对象

(1)函数
(2)函数指针   调用(*fun)();  
(3)lambda表达式
(4)bind 创建的对象
(5)重载了函数调用符的类
函数指针声明
函数返回值类型 (* 指针变量名) (函数参数列表);
eg int(*p)(int, int);
p就是一个指向接收两个int返回一个int的函数的函数指针,调用 p(a,b)
int Func(int x);   /*声明一个函数*/
int (*p) (int x);  /*定义一个函数指针*/
p = Func;          /*将Func函数的首地址赋给指针变量p*/
调用(*p)(6);  ==  Func(6);

函数指针的调用

double y = cal(5);   // 通过函数调用
double y = (*pf)(5);   // 通过指针调用 推荐的写法 
double y = pf(5);     // 这样也对, 但是不推荐这样写 

函数指针做参数

void estimate(int lines, double (*pf)(int));  // 函数指针作为参数传递 

bool (*pf)(string &,string&)
表示pf是一个指向函数的指针,函数接收两个string引用,返回bool值
使用 bool a=pf(“dd”,“ss”);
有时候这个可调用对象你可以把他们看做一个函数地址

什么是lambda

转载

简单来说,Lambda是一个可调用的代码单元。可以理解为一个未命名的内联函数(匿名函数);它的语法定义如下:

[capture](parameters) mutable ->return-type{statement}

可以忽略参数列表和返回类型也就是也已表示为[] {}的形式,当语句块中只有一条==return xxx; 语句的时候返回类型会自动进行推导,而有别的语句的时候返回类型都会被推导为void这时候如果你需要返回类型就需要手动进行指定 []()->bool {}==

1.[capture]:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;

2.(parameters):参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;

3.mutable:mutable修饰符。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);

4.->return-type:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号”->”一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;

5.{statement}:函数体。内容与普通函数一样,不过除了可以使用参数之外,**还可以使用所有捕获的变量。**

与普通函数最大的区别是,除了可以使用参数以外,Lambda函数还可以通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表有以下几种形式:

1.[var]表示值传递方式捕捉变量var;
2.[=]表示值传递方式捕捉所有父作用域的变量(包括this);
3.[&var]表示引用传递捕捉变量var;
4.[&]表示引用传递方式捕捉所有父作用域的变量(包括this);
5.[this]表示值传递方式捕捉当前的this指针。

上面提到了一个父作用域,也就是包含Lambda函数的语句块,说通俗点就是包含Lambda的“{}”代码块。上面的捕捉列表还可以进行组合,例如:

1.[=,&a,&b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量;
2.[&,a,this]表示以值传递的方式捕捉变量a和this,引用传递方式捕捉其它所有变量

不过值得注意的是,捕捉列表不允许变量重复传递。下面一些例子就是典型的重复,会导致编译时期的错误。例如:

erro:
3.[=,a]这里已经以值传递方式捕捉了所有变量,但是重复捕捉a了,会报错的;
4.[&,&this]这里&已经以引用传递方式捕捉了所有变量,再捕捉this也是一种重复。

lambada的函数体未指定返回类型,默认为void

lambda只有在其捕获列表中捕获一个它所在函数的局部变量才能在该函数体中使用

捕获列表只用于局部非static变量,可以直接使用局部static变量和在它所在函数之外声明的名字


#include<iostream>         
using namespace std;       
                           
int main()                 
{                          
    int j = 10;            
    auto by_val_lambda = [=]{ return j + 1; };
    auto by_ref_lambda = [&]{ return j + 1; };
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;
                           
    ++j;                   
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;
                           
    return 0;              
}

output

by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12

你想到了么???那这又是为什么呢?为什么第三个输出不是12呢?

在by_val_lambda中,j被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),而在by_ref_lambda中,j仍然在使用父作用域中的值。所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。

#include<iostream>                  对于const的成员函数,修改非静态的成员变量,所以就出错了。而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了。都是一些纠结的规则。慢慢理解吧。
using namespace std;                
                                    
int main()                          
{                                   
    int val = 0;                                    
    // auto const_val_lambda = [=](){ val = 3; }; wrong!!!
                                    
    auto mutable_val_lambda = [=]() mutable{ val = 3; };
    mutable_val_lambda();           
    cout<<val<<endl; // 0
                                    
    auto const_ref_lambda = [&]() { val = 4; };
    const_ref_lambda();             
    cout<<val<<endl; // 4
                                    
    auto mutable_ref_lambda = [&]() mutable{ val = 5; };
    mutable_ref_lambda();           
    cout<<val<<endl; // 5
                                    对于const的成员函数,修改非静态的成员变量,所以就出错了。而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了。都是一些纠结的规则。慢慢理解吧。
    return 0;      
}

这段代码主要是用来理解Lambda表达式中的mutable关键字的。默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值。例如上面的Lambda表达式可以看成以下仿函数代码:

class const_val_lambda
{
public:
    const_val_lambda(int v) : val(v) {}
    void operator()() const { val = 3; } // 常量成员函数
 
private:
    int val;
};

对于const的成员函数,修改非静态的成员变量,所以就出错了。而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了。都是一些纠结的规则。慢慢理解吧。

lambda也可以捕获this

struct Foo {
  void f() {
    std::unique_ptr<int> p;
    auto f = [=] { cout << p.get() << endl; };
    f();
  }
};

捕获只能针对于在创建lambda式的作用域内可见的非静态局部变量(包括形参)。

也就是说,在函数体外的类成员变量(这里的p)是无法被捕获的,那么为何可以直接访问p呢?
其实是捕获了this指针。

每一个非静态成员函数都持有一个this指针,然后每当提及该类的成员变量时都会用到这个指针。

那么这里也解释通了,其实[=]捕获了this指针,然后编译器看到p.get()时,把它翻译成了this->p.get()。把代码中的[=]改成[this],仍然成功编译。
也就是说,如果this指向的对象已经被析构,捕获this指针的lambda式就可能出现问题,比如下面代码


using namespace std;

struct Foo {
  std::unique_ptr<int> p;
  std::function<void()> f() {
    p.reset(new int(1));
    return [=] { cout << *p << endl; };
  }
};

int main() {
  auto foo = new Foo();
  auto f = foo->f();
  delete foo;
  f();
}

运行结果为0而非1,而且这里输出0是未定义行为,因为访问的实际上是被回收的空间,只是因为编译器的delete并没有对回收的空间做额外的操作,所以p指向的仍然是原来那块,只不过那块已经被unique_ptr的析构函数自动清除了,只不过将清除的部分全部置为0而已。

由于[=]很容易让人忽略掉this也被捕获了,所以很容易让人忽视这个问题,所以不如[this]直观。

bind

bind就是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来适应原对象的参数列表

auto newcallable=bind(callable,arglist)

newcallable就是一个可调用对象:函数,函数指针,lambda表达式,bind,重载()的类;

当我们调用newcallable时候,newcallable会调用callable并传递给它arglist中的参数.

arglist中可能会有_n这种出现,这种叫做占位符,数值n表示可调用对象参数的位置,例如_1代表newcallable的第一个参数

eg

auto wc=bind(check,_1,6);
wc(5);
相当于
check(5,6);

通过pointers to members使用bind

bind将传入的成员(数据成员和成员函数)指针作为第一个参数,其行为如同使用boost::mem_fn将成员指针转换为一个函数对象,即:

bind(&X::f, args); 等价于bind<R>(mem_fn(&X::f), args),其中R为X::f的返回类型(成员函数)或类型(数据成员)。

 1 struct X
 2 {
 3     bool f(int a);
 4 };
 5 
 6 X x;
 7 shared_ptr<X> p(new X);
 8 int i = 5;
 9 
10 bind(&X::f, ref(x), _1)(i);        // x.f(i)
11 bind(&X::f, &x, _1)(i);            // (&x)->f(i)
12 bind(&X::f, x, _1)(i);            // x.f(i)
13 bind(&X::f, p, _1)(i);            // p->f(i)  p是类对象,实例化后的

bind(&X::F,*this,_1)  
相当于
(*this)->F();

所以: 在使用std::bind绑定类成员函数时,一定要注意,不能有要绑定成员函数的重载成员函数,它分不清到底是哪一个

但是可以进行显示的调用

#include <functional>
#include <iostream>
#include <string>

class test {
 public:
  test() {}
  ~test() {}
  void diaplay(std::string value) { std::cout << "string" << value; }

  void diaplay(int value) { std::cout << "int" << value; }
};

int main() {
  test test_;

  auto fun = std::bind((void (test::*)(std::string)) & test::diaplay, &test_,
                       std::placeholders::_1);

  fun("ss");
}

参考

告别命令行!用这个开源的Web版Kettle工具,5分钟搞定数据集成任务编排 本文介绍了一款开源的Web版Kettle工具,通过直观的拖拽界面大幅提升数据集成效率,告别复杂的命令行操作。该工具基于Kettle核心引擎,支持跨平台协作、轻量化访问和降低学习曲线,特别适合业务分析师快速上手。实测显示,使用该工具后任务配置错误率下降62%,协作效率提升40%。 阅读详情

相关推荐

Frida实战:如何用adb快速连接网易mumu模拟器进行参数Hook(附常见CPU架构问题排查)

本文详细介绍了如何使用Frida和adb快速连接网易MuMu模拟器进行参数Hook,包括环境配置、架构适配、Frida-server部署及常见问题排查。特别针对CPU架构兼容性问题提供了实用解决方案,帮助开发者高效完成逆向调试任务。

weixin_29274969的博客 289

C++ Primer笔记——lambda表达式与bind函数

lambda是C++11所规定的一种新方法。一般用于泛型算法传递自定义函数。[ 捕捉列表 ] ( 参数列表 ) ->返回值类型 { 函数体 }lambda表达式会返回一个函数对象。};f(a, b);等价于下列函数{}//按降序排序});使用lambda表达式时,1.捕捉列表可以为空2.尾置返回类型和参数列表可以忽略,即[]{};3.捕捉列表和函数体不能忽略。

weixin_61857742的博客 1540

PyMySQLSaver实战:构建高可靠性的LangGraph状态管理

本文详细介绍了如何使用PyMySQLSaver构建高可靠性的LangGraph状态管理系统。通过检查点机制和MySQL持久化技术,开发者可以确保AI应用在崩溃后从最近状态恢复,支持长时间运行任务和多轮交互。文章包含核心架构解析、生产环境部署指南及实战案例,帮助开发者掌握状态管理的核心技术。

weixin_29310605的博客 494

闭包->函数对象包装器function和bind->lambda表达式

无

liyucheng777的博客 432

[前沿技术] AMD FSR 1.0源码解析:EASU算法实现细节与优化策略

本文深入解析了AMD FSR 1.0技术的核心——EASU(边缘自适应空间升频)算法。通过剖析其源码,详细阐述了EASU如何利用12-tap采样窗口、基于Lanczos滤波器的多项式近似以及自适应的边缘检测机制,在无需AI模型的情况下实现高质量图像放大。文章重点揭示了其极致的GPU优化策略,包括寄存器利用、采样优化和避免动态分支,为理解高性能图形算法提供了绝佳范例。

docker7nomad的博客 540

异步bus交互(一)— 两级DFF同步器

异步bus交互(一)— 两级DFF同步器 跨时钟域处理 & 亚稳态处理 1.问题产生 现在的芯片(比如SOC,片上系统)集成度和复杂度越来越高,通常一颗芯片上会有许多不同的信号工作在不同的时钟频率下。比如SOC芯片中的CPU通常会工作在一个频率上,总线信号(比如DRAM BUS)会工作在另一个时钟频率下,而普通的信号又会工作在另外的时钟频率下。这3个不同时钟频率下工作的信号往往需要相互沟通和传递信号。 不同时钟域下的信号传递就涉及到跨时钟域信号处理,因为相互之间的频率、相位不一样,如果不做处理或者

qq_44816673的博客 5120

【C++】lambda 表达式 / 包装器 / bind 绑定

lambda 表达式的类型是由编译器自动生成的, 并且带有随机值, 是无法具体的写出 lambda 表达式的类型, 并且 lambda 表达式是一个匿名的函数对象(匿名对象生命周期只有一行), 若不立即使用 或 使用 auto 推导赋值给对象, 则会销毁.包装器是一种特殊的类模板, 是适配器的一种, 可以将相同或类似使用方式, 但类型不同的对象, 包装为同一类型, 使其可以达到类似回调函数的效果.下列的函数, 仿函数, lambda 表达式的使用方式相同, 但却会实例化出不同类型的 useF() 函数.

m0_68146877的博客 1082

Centos7.6下安装Zabbix6

一、

Overmaster博客 1906

C++ 三大函数神器:lambda、bind、function 实战详解

lambda 表达式本质是匿名函数对象—— 就是不用给函数起名字,写完就能用,适合实现简单、短期使用的逻辑(比如你的加法逻辑,只用来配合 bind,没必要单独写一个命名函数)std::bind是头文件里的工具,作用是绑定函数的部分参数、调整参数顺序,生成一个新的 “参数调整后” 的函数简单说:它能把一个 “多参数函数” 变成 “少参数函数”(固定部分参数),或者重新排列参数的顺序也是头文件里的工具,它是可调用对象的包装器。

hello world/linux 869

麒麟系统无法进入单用户模式该怎么办?

🏆本文收录于《全栈Bug调优(实战版)》专栏,主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!! 备注:部分问题/疑难杂症搜集于互联网。

**My Coding Family** 1820

机器学习笔记——30种常见机器学习算法简要汇总

本笔记介绍机器学习中常见的30种机器学习算法。

haopinglianlian的博客 3197

【C++11】lambda表达式、包装器、bind 与 placeholders

C++11中引入的新特性:lambda表达式、包装器、bind绑定与placeholders命名空间。本篇博客介绍lambda的书写格式、使用、底层实现原理;包装器,包装器的使用与实际运用;使用bind绑定配合placeholders命名空间使各类函数更好进行包装使用,提高开发效率。

Brant_zero的博客 1460

月薪2万+的网络工程师,到底藏着哪些“绝活”?

在IT圈,网络工程师是个既神秘又硬核的职业。月薪2万+的网工,早已不是只会拉网线、改IP的“IT民工”,而是掌握了一身“绝技”的技术大牛。他们能让企业网络如丝般顺滑,面对宕机临危不乱,还能用自动化脚本批量搞定上百台设备。想知道这些高薪网工的秘密武器是什么?今天,我就以一个老网工的视角,结合自己和同行们的实战经验,扒一扒那些月薪2万+的网络工程师都身怀哪些绝技。如果你也想挤进高薪行列,不妨参考参考!

网络技术联盟站 359

【C++取经之路】lambda和bind

引用一位大佬的一句话——“Use lambdas if you can, and std::bind  if you must.”这句话出自 Scott Meyers 的经典著作《Effective Modern C++》,书中明确指出:与 std::bind相比,lambda几乎在所有方面更优越。

记录代码路上的点滴思考。 1599

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

lambda和function还有bind【C++】

因为全局变量在lambda中本来就能直接使用,没必要捕捉而局部变量根本捕捉不了。

2301_80058734的博客 1538

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

bind和lambda中的拷贝赋值

摘要: C++中的std::bind和Lambda表达式在捕获变量时存在关键差异。std::bind默认执行值拷贝,会立即创建变量的副本存储内部,导致性能浪费,需使用std::ref实现引用传递。而Lambda通过捕获列表提供更灵活的控制,支持按值/引用捕获,特别是C++14的初始化捕获能高效转移资源所有权。对比显示,Lambda在可读性、灵活性及性能上全面占优,是现代C++的首选方案,建议优先使用Lambda表达式替代传统的std::bind。

qq_47987543的博客 915

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

C++11bind、function、lambda详细讲解

最后,祝大家国庆快乐!

2301_79813267的博客 969

Lambda和bind【C++11】

Lambda和bind

qq_2972806103的博客 1081

function,bind,lambda的用法

定义一个std::function对象,例如std::function<void(int)>,可以存储普通函数、Lambda或成员函数(需结合std::bind)。通过std::bind可将成员函数绑定到具体对象,例如:std::bind(&Class::Method, &obj, ...),生成独立的可调用对象。例如,接口需要一个无参函数,但现有函数需要参数,此时可以预先绑定参数。3. 结合std::function:当需要存储或传递不同类型的可调用对象时,通过std::function实现统一接口。

2302_79281982的博客 671

C++中function,bind,lambda

作为find_if的第三个参数,bind1st的作用,首先,将70绑定到二元函数对象(greater)的第一个参数上,其次,将二元函数对象(greater)转为一元函数对象(因为70已知了),传入到find_if的第三个参数中。这里,我们常规的做法通常是:通过一个函数获取集合的最大,最小值,然后保存住,最后在需要的时候访问这两个值,然后打印它们。sort最后一个参数传入的greater或less都被称为函数对象,顾名思义,表现像函数的对象,因为他们的调用都是在后面加上"()"。似乎也没有什么神奇的地方。

gaoyuelong的博客 323

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的区别吗?有了lambda后bind还有多大意义?

本文对比了C++中std::bind与Lambda的差异与应用场景。std::bind作为函数适配器,主要用于绑定成员函数和参数预绑定,而Lambda通过捕获列表实现闭包,语法更简洁。性能上Lambda更具优势,调用开销更低。现代C++建议优先使用Lambda,但std::bind仍适用于参数重排和旧代码兼容等特定场景。开发者应根据需求选择合适方式,但Lambda因其简洁高效已成为主流选择。

行知SLAM 533

Lambda与bind

Lambda 表达式:直接定义回调代码,较为简洁。:将类成员函数绑定为回调,需要定义额外的回调函数,但对于复杂回调,便于代码重用和清晰组织。

2402_87385120的博客 399

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

C++中的function, bind 和 lambda

本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制。之所以把这三块放在一起讲,是因为这三块之间有着非常密切的关系,通过对比学习,加深对这部分内容的理解。在开始之间,首先要讲一个概念,closure(闭包),这个概念是理解lambda的基础。下面我们来看看wikipedia上对于计算机领域的closure的定义:

小邓笔记 8538

bind与lambda

  bind() 和 lambda 表达式都可以实现类似的功能,在使用的时候有时候不知道选择哪一个。这里来做一个简单的总结。主要参考了一下的文章: http://stackoverflow.com/questions/1930903/bind-vs-lambda http://www.gockelhut.com/c++/articles/lambda_vs_bind 1. bind() 在多...

weixin_33754065的博客 209
上一篇: ubuntu 安装--手动分区
下一篇: ros学习之actionlib
黑猫爱小鹿
博客等级 码龄8年 1万+粉丝 205原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值