C++11(三)

简介: C++11

lambda表达式


C++98的栗子


在C++98中,如果要对数据进行排序,当待排数据类型是内置类型时:可以有多种选择,比如,冒泡,归并或者快排;如果待排数据是自定义类型,则需要创建相应的仿函数


举个栗子:将每种球类按照价格的升序进行排序


struct Goods
{
  string _name;
  double _price;
  Goods(const char* str, double price)
  :_name(str)
  , _price(price)
  {}
};
//按照降序进行排
struct Comparepriceless
{
  bool operator()(const Goods& g1, const Goods& g2)
  {
  return g1._price < g2._price;
  }
};
int main()
{
  vector<Goods> v = {{"篮球",50 },{"排球",30},{"羽毛球",20}};
  sort(v.begin(), v.end(), Comparepriceless());
  return 0;
}


运行结果

72ec2a385f42457849e791c60a49ff6b_63055ca4591c4d26af049c0efa4b5e82.png


随着语言的发展,人们觉得上面的方式太麻烦,每次为了实现一个仿函数都是要重新写一个类,如果比较的逻辑不同,还要去实现不同的类,带来了很大的不方便;因此,C++11中出现了lambda表达式来解决这个问题


lambda表达式


使用lambda表达式,修改上面的代码


struct Goods
{
  string _name;
  double _price;
  Goods(const char* str, double price)
  :_name(str)
  , _price(price)
  {}
};
int main()
{
  vector<Goods> v = { {"篮球",50 },{"排球",30},{"羽毛球",20} };
  sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
  return g1._price < g2._price; });
  return 0;
}


运行结果与上面一致


db12c6c63af97787ae3afa3e4fe514e0_8f70a31c5cc0482ebde73be8b1617394.png


lambda表达式语法


语法:[capture-list](parameters)multable->return-type{statement}


[capture-list]:捕捉列表,编译器根据捕捉列表中所捕捉的变量(上文)提供给lambda使用;必须写

(parameters):参数列表,与普通参数列表一致;可省略

multable:默认情况下,lambda函数总是一个const函数,multable可以取消其常量性;使用该修饰时,参数列表不可以省略;可省略

->return-type:返回值类型,可自动推导返回值类型从而声明函数的返回值类型;可省略

{statement}:函数体,在该函数体内,除了可以使用其参数外,还可以使用所捕捉的变量

举个栗子:


int main()
{
  //最简单的lambda表达式,无任何意义
  [] {};
  auto compare = [](int x, int y) {return x > y; };
  cout << compare(1, 0) << endl;
  return 0;
}

e014f3a58d7ff288770aed5d50b8b996_e57f0fea58e84452a4a7aaa5f67a37a4.png


lambda表达式实际上是一个对象,类型无法获得,只能通过auto去推演


捕捉列表说明


[var]:表示值传递方式捕捉变量var

[=]:表示值传递方式捕捉所有父作用域中的变量;所谓父作用域便是lambda函数的语句块

[&var]:表示引用传递方式捕捉变量[var]

[&]:表示引用传递方式捕捉所有父作用域中的变量


函数对象与lambda表达式


观察下列代码


class Rate
{
public:
  Rate(double rate)
  :_rate(rate)
  {}
  //仿函数
  double operator()(double money, int year)
  {
  return money * _rate * year;
  }
private:
  double _rate;
};
int main()
{
  double rate = 0.4;
  Rate r1(rate);
  r1(10000, 5);
  auto r2 = [=](double money, int year) {return money * rate * year; };
  r2(10000, 5);
  return 0;
}



仿函数与lambda表达式完全一样;仿函数将rate作为其成员变量,在定义对象时给出初始值即可;lambda表达式通过捕获列表可以直接将该变量捕获到


仿函数反汇编

591acd1fc6773787dcd802cbf297258e_ca772ec023e94a8a9b698c67bffcce1a.png


lambda表达式反汇编


e7032787ebe742688ca989c4731c506a_7298a948e7cd454ba9b2710fbf2f085e.png


包装器


function包装器


function本质是一个类模板,也是一个包装器


观察下列代码


template<class F,class T>
T useF(F f, T x)
{
  static int i = 0;
  cout << "i:" << ++i << endl;
  cout << "i:" << &i << endl;
  return f(x);
}
double f(double d)
{
  return d / 2;
}
struct Functor
{
  double operator()(double d)
  {
  return d / 2;
  }
};
int main()
{
  //函数名f
  cout << useF(f, 1.1) << endl;
  //仿函数Functor
  cout << useF(Functor(), 1.1) << endl;
  //lambda表达式
  cout << useF([](double d){ return d / 4; }, 1.1) << endl;
  return 0;
}


运行结果


90ec6c3bafbf258f6ffafc0fdd495f7d_c0d751ea223048749deab620064fedab.png


首先变量i是静态,本应该生成一份,但结果却是生成了三份,而且代码中调用的方式并不统一;接下来使用function统一调用方式


类模板原型如下


Ret:被调用函数的返回类型
Args...:被调用函数的形参
template<class Ret,class... Args>
class function<Ret(Args...)>


举个栗子:


int f(int a, int b)
{
  return a + b;
}
struct Functor
{
  int operator()(int a, int b)
  {
  return a + b;
  }
};
int main()
{
  //函数名/函数指针
  function<int(int, int)> f1(f);
  cout << f1(1, 2) << endl;
  //仿函数
  function<int(int, int)>f2=Functor();
  cout << f2(1, 2) << endl;
  //lambda表达式
  function<int(int, int)>f3 = [](const int a, const int b) {return a + b; };
  cout << f3(1, 2) << endl;
  return 0;
}


56f82ae28167b4b907e575b49a0fd119_3abf684d158844d2be4e2e99f752d553.png


包装器的可以将函数指针/仿函数/lambda表达式进行类型统一,使用一种方式进行调用


bind


上面的function是类模板,这里的bind是一个函数模板,接受一个可调用对象,生成一个新的可调用对象来适配原对象的参数列表


原型如下


template<class Ret,class... Args>
bind(Fn&& fn,Args&&... args)


这里的参数包是由命名空间placeholders构成


ace96f9d4c89a24689f9cd75a6938b9e_22a29cfe55a84cf39ce3453073c9bbf6.png


举个栗子:


int Plus(int a, int b)
{
  return a + b;
}
int Sub(int a, int b)
{
  return a - b;
}
int main()
{
  //绑定函数Plus,参数分别调用func1的第一个,第二个参数
  function<int(int, int)>func1 = bind(Plus, placeholders::_1, placeholders::_2);
  cout << func1(1, 2) << endl;
  //绑定函数Sub,参数分别调用func2的第一个,第二个参数
  function<int(int, int)>func2 = bind(Sub, placeholders::_1, placeholders::_2);
  cout << func2(1, 2) << endl;
  return 0;
}

06e7e3dd085591d0f261a0f12dc227bd_fa3858647a2f49e695f37a65ae998005.png


目录
相关文章
|
安全 NoSQL 网络协议
Discuz-ssrf攻击redis getshell(Gopher协议)
不知不觉踏入安全已经有段时间了...这个过程的确很艰辛,很累,随着突发奇想的那一刻,决定了一直走下去,这期间几乎是没日没夜地去学习,忘记了时间,放弃了很多其他事情,学习之路真的不是那么简单,有时候甚至会很迷茫,不知该如何走下去了...
321 0
|
druid Java 关系型数据库
Java通用方法 -- Druid加密Mysql数据库
生产环境部署,若包含密码配置时使用明文,客户会很嫌弃,介绍一种数据库密码加密方法,借助阿里的druid,
171 0
|
自然语言处理 异构计算
Paper:2017年的Google机器翻译团队《Transformer:Attention Is All You Need》翻译并解读(三)
Paper:2017年的Google机器翻译团队《Transformer:Attention Is All You Need》翻译并解读
|
机器学习/深度学习 算法
深度残差收缩网络(1):背景知识
深度残差收缩网络,英文名为Deep Residual Shrinkage Network,是深度残差网络(Deep Residual Network, ResNet)的一种改进,发表在IEEE Transactions on Industrial Informatics上,面向的是数据含有噪声的情况。
深度残差收缩网络(1):背景知识
|
大数据 分布式计算 Hadoop
【转载】阿里云飞天大数据平台亮相
7月25日,阿里云飞天大数据平台亮相阿里云峰会上海站,拥有中国唯一自主研发的计算引擎,是全球集群规模最大的计算平台,最大可扩展至10万台计算集群,支撑海量数据存储和计算。在民生服务领域,飞天大数据平台已经“最多跑一次”、城市大脑等场景中,协助政府优化服务模式,实现更智能便捷的服务能力,保障信息安全。
3595 0
|
Web App开发 Linux
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
内存是影响Linux性能的主要因素之一,内存资源的充足与否直接影响应用系统的使用性能。 free命令:监控Linux内存使用状况。
1155 0
|
自然语言处理 关系型数据库 MySQL