c++11相关语法与lambda表达式

1.初始化问题
int array1[] = {1,2,3,4,5};
int array2[5] = {0};
C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
内置类型的列表初始化
int main()
{
// 内置类型变量
int x1 = {10};
int x2{10};
int x3 = 1+2;
int x4 = {1+2};
int x5{1+2};
// 数组
int arr1[5] {1,2,3,4,5};
int arr2[]{1,2,3,4,5};
// 动态数组,在C++98中不支持
int* arr3 = new int[5]{1,2,3,4,5};
// 标准容器
vector v{1,2,3,4,5};
map<int, int> m{{1,1}, {2,2,},{3,3},{4,4}};
return 0;
}
标准库支持的那个对象列表的初始化
class Point
{
public:
Point(int x = 0, int y = 0): _x(x), _y(y)
{}
private:
int _x;
int _y;
};
int main()
{
Pointer p{ 1, 2 };
return 0; }
2. 多个对象的列表初始化
多个对象想要支持列表初始化,需给该类(模板类)添加一个带有initializer_list类型参数的构造函数即可。注意:initializer_list是系统自定义的类模板,该类模板中主要有三个方法:begin()、end()迭代器
以及获取区间中元素个数的方法size()。

#include <initializer_list>
template<class T>
class Vector {
public:
// ... 
Vector(initializer_list<T> l): _capacity(l.size()), _size(0)
 {
_array = new T[_capacity];
for(auto e : l)
_array[_size++] = e;
 }
Vector<T>& operator=(initializer_list<T> l) {
delete[] _array;
size_t i = 0;
for (auto e : l)
_array[i++] = e;
return *this;
 } 
// ...
private: T* _array;
size_t _capacity;
size_t _size;
};

3.变量类型推导
C++11中,可以使用auto来根据变量初始化表达式类型推导变量的实际类型,可以给程序的书写提供许多方便。将程序中c与it的类型换成auto,程序可以通过编译,而且更加简洁
auto
使用的前提是:必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型
decltype
类型推导–是根据表达式的实际类型推演出定义变量时所用的类型
1.推演表达式类型作为变量的定义类型
int a = 10;
int b = 20;
// 用decltype推演a+b的实际类型,作为定义c的类型
decltype(a+b) c;
cout<<typeid©.name()<<endl;
2 推演函数返回值的类型
4. void* GetMemory(size_t size) {
return malloc(size);
}
int main()
{
// 如果没有带参数,推导函数的类型
cout << typeid(decltype(GetMemory)).name() << endl;
// 如果带参数列表,推导的是函数返回值的类型,注意:此处只是推演,不会执行函数
cout << typeid(decltype(GetMemory(0))).name() <<endl;
return 0; }
4范围for—本质底层是迭代器支持迭代器一定支持 范围for
5 委派构造函数
所谓委派构造函数:就是指委派函数将构造的任务委派给目标构造函数来完成的一种类构造的方式。—定义不同类型进行初始化
在初始化列表中调用”基准版本”的构造函数称为委派构造函数,而被调用的”基准版本”则称为目标构造函数。
class Info{
public:
// 目标构造函数
Info(): _type(0), _a(‘a’)
{ InitRSet();}
// 委派构造函数
Info(int type): Info()
{ _type = type;}
// 委派构造函数
Info(char a): Info()
{ _a = a;}
private:
void InitRSet(){ //初始化其他变量 }
private:
int _type = 0;
char _a = ‘a’;
//…
};
6 lambda表达式
首先举个例子
如果对自定义类型进行排序需要用户指定排序规则
struct Goods
{
string _name;
double _price;
};
struct Compare
{
bool operator()(const Goods& gl, const Goods& gr)
{
return gl._price <= gr._price;
}
};
int main()
{
Goods gds[] = { { “苹果”, 2.1 }, { “相交”, 3 }, { “橙子”, 2.2 }, {“菠萝”, 1.5} };
sort(gds, gds+sizeof(gds) / sizeof(gds[0]), Compare());
return 0; }
人们开始觉得上面的写法太复杂了,每次为了实现一个algorithm算法, 都要重新去
写一个类,如果每次比较的逻辑不一样,还要去实现多个类,特别是相同类的命名,这些都给编程者带来了
极大的不便。因此,在C11语法中出现了Lambda表达式

int main()
{
Goods gds[] = { { "苹果", 2.1 }, { "相交", 3 }, { "橙子", 2.2 }, {"菠萝", 1.5} };
sort(gds, gds + sizeof(gds) / sizeof(gds[0]), [](const Goods& l, const Goods& r)
 {
return l._price < r._price;
 });
return 0; 
}
可以看出lamb表达式实际是一个匿名函数
lambda表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement }

1.lambda表达式各部分说明
[]捕捉列表
()参数列表
->type 返回值类型
{}函数体实现
注意: 在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空
最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情。

捕捉列表描述了上下文中那些数据可以被lambda使用,以及使用的方式传值还是传引用。
[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针
注意:
a. 父作用域指包含lambda函数的语句块
b. 语法上捕捉列表可由多个捕捉项组成,并以逗号分割。
比如:[=, &a, &b]:以引用传递的方式捕捉变量a和b,值传递方式捕捉其他所有变量 [&,a, this]:值传递方式捕捉变量a和this,引用方式捕捉其他变量 c. 捕捉列表不允许变量重复传递,否则就会导致编译错误。 比如:[=, a]:=已经以值传递方式捕捉了所有变量,捕捉a重复
c. 在块作用域以外的lambda函数捕捉列表必须为空。
d. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量,捕捉任何非此作用域或者非局部变量都
会导致编译报错。
e. lambda表达式之间不能相互赋值,即使看起来类型相同

eg:
实现a+b
int a =1,b=2;捕捉列表和参数列表
auto add=[](int x1,int x2)-> int{return x1+x2;};//(范围for也是)
cout<<add(1,2)<<endl;
cout<<add(1,2)<<endl;
函数对象:
函数对象,又称为仿函数,即可以像函数一样使用的对象,就是在类中重载了operator()运算符的类对象。

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.49;
Rate r1(rate);
r1(10000, 2);
// 仿函数
auto r2 = [=](double monty, int year)->double{return monty*rate*year; };
r2(10000, 2);
return 0; }
从使用方式上来看,函数对象与lambda表达式完全一样。

函数对象将rate作为其成员变量,在定义对象时给出初始值即可,lambda表达式通过捕获列表可以直接将该变量捕获到。
底层原理
lambda是现定义现用
实现原理-
<lanbda_uuid>::operator()
实现原理:实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类重载了operator()

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值