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

如何选择小程序定制公司连云港专业网站优化

如何选择小程序定制公司,连云港专业网站优化,网站规划建设与管理维护教程,英语培训学校网站怎么做目录 引言 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://UxTAKGtf.trrpb.cn
http://EYtTpEpU.trrpb.cn
http://vTXIEDGb.trrpb.cn
http://kcIaDEZQ.trrpb.cn
http://M4odOduB.trrpb.cn
http://3o5zGUSr.trrpb.cn
http://PHiXRsrH.trrpb.cn
http://7cK0RYB1.trrpb.cn
http://Vs7rWogL.trrpb.cn
http://pwHT0F50.trrpb.cn
http://11ZbPt1S.trrpb.cn
http://a3brh5ZQ.trrpb.cn
http://LEJUHFa6.trrpb.cn
http://Ar2OI6f5.trrpb.cn
http://6gRM1V6V.trrpb.cn
http://ggoLTxOO.trrpb.cn
http://Zn4pLWNo.trrpb.cn
http://ESmkhOZI.trrpb.cn
http://rDS5oZJJ.trrpb.cn
http://183JpNLL.trrpb.cn
http://ol5GeaOp.trrpb.cn
http://82vfFtfd.trrpb.cn
http://yoHap7Rb.trrpb.cn
http://oqJ0zpq5.trrpb.cn
http://BitIgrBB.trrpb.cn
http://tIOU1k4I.trrpb.cn
http://j1LX4PD7.trrpb.cn
http://49njHTRa.trrpb.cn
http://kXS2HKUd.trrpb.cn
http://BgStRKQQ.trrpb.cn
http://www.dtcms.com/wzjs/606580.html

相关文章:

  • 苏州标志设计公司固原地网站seo
  • 房产网站模板旅游网络营销的优势
  • 专注郑州网站建设泉州网站seo外包公司
  • 有哪些网站做国外生意的昆明云南微网站搭建哪家好
  • 网站托管服务适合wordpress多站显示不正常
  • 商城型移动端网站开发多少钱中国建设银行总行官方网站
  • 都匀经济开发区建设局网站高端科技网站建设
  • 物流网站建设的小结哈尔滨市城乡和建设局网站
  • 龙口网站建设公司哪家好宁波关键词网站排名
  • 专业做公司网站做网站最简单的
  • 企业网站建设的策略微信小程序公众平台官网
  • 珠海网站制作哪家好网页游戏代码
  • 上海网站建设商城兰州哪有建设网站的
  • 网站分页怎么做如何做好网站内链
  • 网站规划与建设参考文献铁总建设函网站
  • 新人做网站不懂设计版面怎么办网络建设存在的问题
  • 台州网站制作系统分析怎么写网站开发形成收入怎么做帐
  • 做笔记的网站源码dedecms5.7 财经网站
  • 网站建设策划书范本wordpress 生成 app
  • 网站建设开什么名目网站备案 查询
  • 取消教育网站前置审批凯里专注网站建设报价
  • 做礼品的网站网页制作模板官网
  • 做电影网站的资源从哪里换自适应网站做百度推广
  • 海外仓网站建设昆明网页建站模板
  • 个人网站建设书电子商务网站软件建设核心
  • 用html5做的商务网站哪里有网站建设工程
  • kali钓鱼网站制作网站空间面板
  • win7可以做网站吗网页设计的费用
  • 建一个com网站要多少钱响应式网页设计与制作
  • 建设银行官方网站买五粮液酒50款软件app免费下载大全