当前位置: 首页 > wzjs >正文

美发企业网站建设价格足球世界积分榜

美发企业网站建设价格,足球世界积分榜,铁岭开原网站建设,linux主机上wordpress的url伪静态化优化技巧目录 引言 lambda语法 lambda捕获列表解析 1)值捕获 2)引用捕获 3)隐式捕获 lambda的工作原理 lambda进阶用法 泛型lambda 立即调用 lambda 与 function bind语法 bind的调用逻辑 bind核心用途 绑定参数 调整参数顺序 bind的…

目录

引言

lambda语法

lambda捕获列表解析

1)值捕获

2)引用捕获

3)隐式捕获

lambda的工作原理

lambda进阶用法

泛型lambda

立即调用 

lambda 与 function

bind语法

bind的调用逻辑 

bind核心用途

绑定参数

调整参数顺序

bind的陷阱

bind绑定成员函数

结语


引言

Lambda 是现代 C++(C++11 及之后)引入的核心特性,它使得定义匿名函数(即未命名的代码块)更加便捷,尤其是在需要临时传递函数逻辑时,在写算法题时经常用到,就比如sort默认的排序逻辑(升序)不是我们想要的,我们想要的是降序排列,那么给sort传递一个lambda来排序就很方便。

bind是C++11 标准库中的一个关键工具,可以把它看做是一个函数适配器,它接受一个可调用对象,然后生成一个新的可调用对象来适配原对象的参数列表。

光说概念很抽象,下面会举例子来说明。

lambda语法

[ 捕获列表 ] ( 参数列表 ) -> 返回类型 { 函数体 }

可以看到,lambda表达式主要由5个部分组成。除了捕获列表和函数体,其他的都可以忽略。下面是一个简单的lambda表达式,主要是用来熟悉它的语法。

	auto lambda = [](int a, int b) {return a + b; };cout << lambda(1, 2);//输出3

上述的lambda表达式中,捕获列表为空,参数列表有两个,调用时传入,和普通函数调用传参一样,并没什么特别的,返回类型省略了,因为这种情况下它可以自己推导返回类型。具体什么情况下不能省略这里就不列举啦,当省略后编不过在把返回类型加上即可。总之,规范使用可以避免很多不必要的麻烦。

lambda捕获列表解析

lambda表达式中,最值得谈的当然是它的捕获列表啦。

捕获方式

语法

效果

按值捕获

[x]

复制外部变量 x 的值到 Lambda 对象中

按引用捕获

[&x]

引用外部变量 x,Lambda 内修改会影响原变量

捕获全变量(值)

[=]

所有外部变量按值捕获(存在悬挂引用风险,需谨慎!)

捕获全变量(引用)

[&]

所有外部变量按引用捕获(可能无意中修改外部状态,慎用!)

混合捕获

[x, &y]

按值捕获 x,按引用捕获 y

捕获 this

[this] 或 [=]

隐式捕获类的 this 指针,可访问类成员变量

 

可以看到,lambda的捕获方式可谓是花里胡哨,下面谈谈不同捕获方式的区别。

1)值捕获

int main()
{int x = 10;auto lambda = [x](int y) {return x + y; };cout << lambda(20);//输出30return 0;
}

采用值捕获,就是要对捕获的变量进行拷贝,和函数传递参数是采用值传递一样。 只有捕获了该变量才能在lambda的函数体内使用。比如下面的写法就是错误的。

int main()
{int x = 10, t = 30;auto lambda = [x]() {return x + t; };//errorreturn 0;
}

 

采用值捕获时,还有一个细节,就是lambda函数体内部不能修改通过值捕获进来的变量。 以下是个错误示范。

int main()
{int x = 10;auto lambda = [x]() {return x++; };//errorreturn 0;
}

如果非要修改,也是有办法的。介绍一个关键字——mutable。

int main()
{int x = 10;auto lambda = [x]()mutable {return x++; };//正确return 0;
}

 在参数列表后加上mutable关键字即可。

2)引用捕获

int main()
{int x = 10;auto lambda = [&x](int y) {x += 10;return x + y;};lambda(20);cout << x << endl;//输出20return 0;
}

引用捕获和函数采用引用方式传递参数是一个道理,不会进行拷贝,lambda函数体内如果对引用捕获的变量进行修改,外部的也就跟着被修改了,本质上就是修改同一个地址的值。 

在采用引用捕获时需要注意的一点是:一定要注意所引用对象的生命周期,避免出现野指针。这一点和函数调用结束后返回一个局部变量的引用是一样的道理,在函数调用结束后,局部变量就已经被销毁了,这时引用的地址早就被释放了,再去访问程序就该崩了。

3)隐式捕获

除了我们在捕获列表中显示的指出要捕获哪些变量外,也可以让编译器根据lambda函数体中的代码来推断我们需要捕获哪些变量。即编译器自己推导捕获列表。

int main()
{int x = 10;auto lambda = [=](int y) {return x + y; };//采用值捕获的隐式捕获auto lambda = [&](int y) {return x + y; };//采用引用捕获的隐式捕获return 0;
}

当我们混用显示捕获和隐式捕获时,必须把=或&放在第一个,比如这样 [=,&x],还有一点就是明明已经采用隐式的值捕获了,又在捕获列表中采用值捕获其他变量,这是不允许的,也大可不必。比如这么写就是不对的[=,x]。总之,还是那句话——规范使用可以避免很多不必要的麻烦。 

lambda的工作原理

Lambda 在编译时会生成一个匿名类(称为闭包类),其中捕获的变量就会以成员变量的形式存储,然后该闭包类中还重载了调用运算符,也就是重载了()。下面举个例子。

// Lambda: [x](){ return x * 2; }
class __Lambda_123 { // 编译器生成唯一类名
private:int x;  // 捕获的变量
public:__Lambda_123(int x_) : x(x_) {}int operator()() const { return x * 2; }
};

lambda表达式本身就是一个闭包类的实例,也就是闭包类的一个对象。在调用lambda()时,实际上调用的是该闭包类内重载的operator()()函数。 

lambda进阶用法

泛型lambda

以auto作为参数类型。

int main()
{auto print = [](const auto& arg) {cout << arg << endl; };print(20);print("hello world!");return 0;
}

立即调用 

定义后立即执行。

int result = [](int a, int b) { return a + b; }(3, 4); // result = 7

lambda 与 function

function是一个函数包装器,它可以将不同形式的可调用对象(如 Lambda、函数指针等)封装到同一类型中。

function<int(int, int)> func = [](int a, int b) {return a + b; };

关于lambda就说到这啦,下面谈谈bind。

bind语法

#include <functional>  // 必须包含的头文件auto bound_fn = std::bind(FuncPointer,      // 原始函数指针/可调用对象Arg1, Arg2, ...,  // 绑定的参数(可包含占位符)ArgN
);

下面提供个简单代码来熟悉bind的语法。

#include <iostream>
#include <functional>
using namespace std;int Sum(int a, int b){return a + b;}
int main()
{auto boundSum = bind(Sum, 10, placeholders::_1);cout << boundSum(20);//输出30return 0;
}

bind的调用逻辑 

auto boundSum = bind(Sum, 10, placeholders::_1);

bind预先把10绑定到了Sum的第一个参数上,Sum(10, placeholders::_1),placeholders::_1是调用的时候传进来的参数。bind还会把参数拷贝给新的调用对象boundSum,所以如果bind中的有的参数不允许拷贝(输入输出流),那么只能用引用,调用库函数ref,ref(ostream)传递。

bind核心用途

绑定参数

void printSum(int a, int b) { std::cout << a + b << "\n"; 
}// 绑定a=10,剩下参数由调用时提供
auto boundPrint = std::bind(printSum, 10, std::placeholders::_1);boundPrint(20); // 输出 30(等价于 printSum(10,20))

这段代码就是绑定了printSum的第一个参数,第二个参数调用时在传进来。

调整参数顺序

//f是一个可调用对象,它有5个参数
auto g = bind(f, a, b, placeholders::_2, c, placeholders::_1);

f的第一个、第二个和第四个参数被绑定到了a、b、c上。调用g时,假设这样调用g(X, Y),那么会调用 f (a,b,Y,c,X)。这样子参数顺序就变了。所以占位符的作用顾名思义,就是占着那个坑,调用传参的时候在用参数替代掉占位符。 这里不仅体现了bind可以改变参数顺序的作用,还体现出了——可以把bind看做是一个函数适配器,它接受一个可调用对象,然后生成一个新的可调用对象来适配原对象的参数列表(引言中的抽象概念)。f 原本是需要5个参数的,bind之后,生成的新的可调用对象g就只需要传递两个参数。

bind的陷阱

#include <iostream>
#include <functional>
using namespace std;class MyClass
{
public:int Method(int y){_x += 10;return _x + y;}
private:int _x = 10;
};
int main()
{MyClass *obj = new MyClass();auto boundMethod = bind(&MyClass::Method, obj, 10);delete obj;//!!!boundMethod();//未定义行为return 0;
}

通过上面的代码,想说明的一点是:一定要注意对象的生命周期。

bind绑定成员函数

比起绑定普通的函数,bind在绑定成员函数时有更多的细节,稍不注意就写错了,得不到期望的结果。

成员函数和普通函数之间,成员函数多了一个this指针,它不能独立于对象存在,必须指明它是哪个对象的成员函数。

MyClass obj;
1) auto boundMethod = bind(MyClass::Method, obj, 10);
2) auto boundMethod = bind(&MyClass::Method, obj, 10);
3) auto boundMethod = bind(&MyClass::Method, &obj, 10);

4) auto boundMethod = bind(&MyClass::Method, ref(obj), 10);

下面着重讲讲上面这四种写法的区别。

1)第一种写法,是错误的。 但是这么写 bind(&MyClass::Method, obj, 10); 又是对的。原因在于bind的第一个参数是函数指针或者可调用对象,但是单纯只有类名+函数名MyClass::Method并不是函数地址。因为C++语法规定,成员函数指针必须通过&类名::成员函数名的方式获取,这和普通函数不一样。比如普通函数func,在使用func时会被隐式转换为函数指针,但是成员函数不会。所以第一种写法是错误的,&符号必须得加上。

2)第二种写法和第三种写法的区别在于有没有对obj取地址,我们知道,bind是会对参数进行拷贝的,如果采用第二种写法,那么在调用boundMethod的时候,调用的是拷贝后的obj对象里的Method,所做的修改不会影响原对象obj。并不是说这种写法是不对的,但是可能这不是我们想要的结果。

3)第三种写法就是对obj取地址,这样bind内部直接使用的是原来的obj对象,Method方法里做的修改在原obj中可以看到。

4)第四种写法就是对obj的引用,bind内部直接绑定到原始对象obj,Method方法里做的修改在原obj中也可以被看到。

传递方式

含义

示例

按值传递对象 obj

生成一个 obj 拷贝,绑定到拷贝后的对象(可能导致状态不一致)

std::bind(&MyClass::Method, obj, ...)

按引用传递 std::ref(obj)

绑定到原始对象,但需确保对象生命周期在调用时有效

std::bind(&MyClass::Method, std::ref(obj), ...)

按指针传递 &obj

直接使用指针指向的原始对象

std::bind(&MyClass::Method, &obj, ...)

结语

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


感谢支持!

http://www.dtcms.com/wzjs/434954.html

相关文章:

  • 一般使用的分辨率是多少dpi?上海哪家seo好
  • 伪静态网站免费制作永久个人网站
  • 产品做国外网站有哪些女教师遭网课入侵直播录屏曝
  • 诚聘网站开发温岭网络推广
  • wordpress 作者 英文seo搜索引擎入门教程
  • 小程序一年服务费多少钱seo优化轻松seo优化排名
  • 浙江网站开发现在搜什么关键词能搜到网站
  • 中小型企业 公司网站建设谷歌优化推广
  • 自己开网站工作室谷歌推广技巧
  • 网站建设资源库最新黑帽seo培训
  • 可靠的邢台做网站长春网站seo公司
  • 显示网站翻页代码品牌seo推广
  • 做网站开发所需的知识技能四年级2023新闻摘抄
  • 医院网站建设报告百度营销是什么
  • 骏域网站建设专家电脑版网红推广
  • 外贸平台网站的营销方式企业老板培训课程
  • 自己用模板做网站上海市人大常委会
  • 公司 网站 苏州关键词在线试听
  • 山西设计网站公司推广策划
  • 同一个域名在一个服务器做两件网站外贸网站推广方法之一
  • 泉州建设局网站软文广告有哪些
  • 软件服务外包优化服务公司
  • 用花生壳做网站百度号码
  • 学校网站建设系统外贸如何做网站推广
  • 网站建设哈尔滨网站建设1网购网站十大排名
  • 做网站策划案企业网络营销成功案例
  • 咸阳做网站的公司百度极速版app下载安装挣钱
  • 政务网站建设总结十大最靠谱教育培训机构
  • 做网站常用的背景图像365优化大师软件下载
  • 网站建设微信商城多少钱百度百科合作模式