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

ps制作网站logo/关联词有哪些类型

ps制作网站logo,关联词有哪些类型,湖南乔口建设公司网站,网站建设 你真的懂吗文章目录 (一)C11新增功能1.1 引用折叠1.1.1 在模板中使用引用折叠的场景1.1.2 引用折叠是如何实现的 1.2 完美转发1.3 lambda表达式语法1.3.1 定义1.3.2 lambda的使用场景1.3.3 捕捉列表1.3.4 mutable语法1.3.5 lambda的原理 (一&#xff09…

文章目录

  • (一)C++11新增功能
    • 1.1 引用折叠
      • 1.1.1 在模板中使用引用折叠的场景
      • 1.1.2 引用折叠是如何实现的
    • 1.2 完美转发
    • 1.3 lambda表达式语法
      • 1.3.1 定义
      • 1.3.2 lambda的使用场景
      • 1.3.3 捕捉列表
      • 1.3.4 mutable语法
      • 1.3.5 lambda的原理

(一)C++11新增功能

1.1 引用折叠

C++中不能直接定义引用的引用,如int& && r = i ;,但是可以间接定义引用的引用,一般情况可以用typedef或者using关键字来实现

int main()
{//int i = 0;//int&&& r = i; //直接定义引用的引用是错误的typedef int& lref;using rref = int&&;int n = 10;//间接引用lref& r1 = n;lref&& r2 = n;rref& r3 = n;rref&& r4 = 1;return 0;
}

上面的代码中,通过模板或者typedef中的类型操作可以构成引用的引用,C++11中把这样的场景叫作引用折叠,它的折叠逻辑是,右值引用的右值引用折叠成右值引用,有左值引用的组合均被折叠成左值引用,所以代码中r1的类型是int&,r2的类型是int&,r3的类型是int&,只有r4的类型是int&&

1.1.1 在模板中使用引用折叠的场景

左值引用模板:

template<class T>
void f1(T& t) 
{ }int main()
{int i = 10;//没有折叠,实例化->f1(int& t);f1<int>(i);f1<int>(0); //报错//有折叠,实例化->f1(int& t);f1<int&>(i);f1<int&&>(0); //报错//有折叠,实例化->f1(int& t);f1<int&&>(i);f1<int&&>(0); //报错//有折叠,实例化->f1(const int& t);f1<const int&>(i);f1<const int&&>(0); //被const修饰的int& 可以引用左值,也可以引用右值return 0;
}

右值引用模板:

template<class T>
void f2(T&& t) //右值引用的模板
{ }int main()
{int i = 10;//没有折叠,实例化->f2(int& t);f2<int>(i);f2<int>(0); //报错//有折叠,实例化->f2(int& t);f2<int&>(i);f2<int&>(0); //报错//有折叠,实例化->f2(int&& t);f2<int&&>(i); //报错f2<int&&>(0);//有折叠,实例化->f2(const int& t);f2<const int&>(i);f2<const int&>(0); //被const修饰的int& 可以引用左值,也可以引用右值return 0;
}

总结:第一个模板为左值引用,由于折叠限定,实例化出来的都是左值引用,第二个模板为右值引用,由于折叠限定,实例化出来的可以为左值引用,也可以为右值引用,即第二个模板通常被称为“万能引用”

1.1.2 引用折叠是如何实现的

证明如下:

template<class T>
void func(T&& t) //右值引用模板
{int a = 0;T x = a;x++;std::cout << &a << std::endl;std::cout << &x << std::endl;
}
int main()
{func(10);//10是右值,则推导出来的T是int,实例化->func(int&& t);//func函数中,x++,a与x的地址不相同int b = 0;func(b);//b是左值,则推导出来的T是int&,实例化->func(int& t);//func函数中,x是a的别名,x++相当于a++,两者地址相同func(std::move(b));//std::move(b)是右值,则推导出来的T是int,实例化->func(int&& t);//func函数中,x++,a与x的地址不相同const int a = 11;func(a);//a是左值,则推导出来的T是const int&,实例化->func(const int& t);// func函数中,x是a的别名,x被const修饰不能进行赋值操作,两者地址相同func(std::move(a));//std::move(a)是右值,则推导出来的T是const int,实例化->func(const int&& t);//func函数中,x被const修饰不能进行赋值操作,两者地址不相同return 0;
}

总结:当实参是左值时,编译器会自动推导模板参数的类型为int&,发生引用折叠,使得左值引用均折叠成左值引用,当实参是右值时,编译器会自动推导模板参数的类型为int,不发生引用折叠,就还是右值引用

1.2 完美转发

看下面代码:

void fun(int& t) { std::cout << "左值引用" << std::endl; };
void fun(const int& t) { std::cout << "const左值引用" << std::endl; };
void fun(int&& t) { std::cout << "右值引用" << std::endl; };
void fun(const int&& t) { std::cout << "const右值引用" << std::endl; };template<class T>
void Func(T&& t)
{fun(t);
}int main()
{Func(10);//右值,推导出来的T为int,实例化->Func(int&& t);int a = 11;Func(a);//左值,推导出来的T为int&,实例化->Func(int& t);Func(std::move(a));//右值,推导出来的T为int,实例化->Func(int&& t);const int b = 22;Func(b);//左值,推导出来的T为const int&,实例化->Func(const int& t);Func(std::move(b));//右值,推导出来的T为const int,实例化->Func(const int&& t);return 0;
}

该代码,通过万能模板调用Func函数,然后再调用fun函数,实现根据不同的值的属性调用到对应的fun函数,如,10是右值就调用对应fun函数的右值引用;a是左值就调用对应fun函数的左值引用,我们来看运行结果

在这里插入图片描述
结果未达到我们的预期,是右值的没有匹配到对应的右值函数,这是因为,右值引用的属性还是左值,所以就会出现全是左值的情况,为了解决以上这种问题,C++11库中实现了一个功能“完美转发”,forward,该功能就是保持原来的属性,实现是左值引用的就保持左值属性,右值引用的就保持右值属性,该接口的本质实际上还是类型强转,使用方法如下:

template<class T>
void Func(T&& t)
{//将原代码改成这样即可fun(std::forward<T>(t));
}

在这里插入图片描述

1.3 lambda表达式语法

1.3.1 定义

lambda表达式本质是一个匿名函数对象,跟普通函数不同的是它可以定义在函数内部。lambda表达式对于语法使用层面而言没有类型,所以一般是用auto或者函数模板参数定义的对象去接收lambda对象

lambda表达式的格式:capture-list->return type{function body}

  • capture-list:捕捉列表,该列表总是出现在lambda函数的开始,编译器根据捕捉列表来判断接下来的代码是否为lambda函数。捕捉列表能够捕捉上下文中的变量lambda函数使用,捕捉列表可以通过传值和传引用捕捉,捕捉列表为空也不能省略
  • parmeters:参数列表。不传参时可以连同()一同省略
  • return type:返回类型,用于追踪返回类型形式声明函数的返回值类型,没有返回值时,可以省略。一般返回值类型明确的情况下,也可以省略,由编译器对返回值类型进行推导。
  • function body:函数体

用法示例:

int main()
{auto add = [](int x, int y)->int {return x + y; };std::cout << add(1, 2) << std::endl;auto func = [] //参数列表和返回值省略{std::cout << "hello world" << std::endl;};return 0;
}

1.3.2 lambda的使用场景

在学习lambda之前,可调用对象只有函数指针和仿函数对象,但函数指针的类型定义起来比较麻烦,仿函数要定义一个类,相对来说也会比较麻烦。使用lambda去定义可调用对象,既简单又方便

看下面代码:

#include <vector>
#include <iostream>
#include <algorithm>
struct goods
{std::string _name; //商品名称double _price; //价格int _evaluate; //评估goods(const char* name,double price,int evaluate):_name(name),_price(price),_evaluate(evaluate){ }
};
struct comparePriceLess
{bool operator()(const goods& lg, const goods& rg){return lg._price < rg._price;}
};
struct comparePriceGreater
{bool operator()(const goods& lg, const goods& rg){return lg._price > rg._price;}
};
int main()
{std::vector<goods> list = { {"苹果",1.2,2},{"香蕉",1.5,3},{"葡萄",2.1,5} };//对商品按价格进行排序std::sort(list.begin(), list.end(), comparePriceLess());std::sort(list.begin(), list.end(), comparePriceGreater());return  0;
}

代码中可以看到,通过实现仿函数对象或函数指针来支持不同项的比较,相对来说还是比较麻烦的,要实现好多个我们所需要的仿函数,那么lambda就很好的解决了这一点

代码如下:

#include <vector>
#include <iostream>
#include <algorithm>
struct goods
{std::string _name; //商品名称double _price; //价格int _evaluate; //评估goods(const char* name,double price,int evaluate):_name(name),_price(price),_evaluate(evaluate){ }
};
int main()
{std::vector<goods> list = { {"苹果",1.2,2},{"香蕉",1.5,3},{"葡萄",2.1,5} };auto priceLess = [](const goods& lg, const goods& rg){return lg._price < rg._price; };//对价格进行排序std::sort(list.begin(), list.end(), priceLess);std::sort(list.begin(), list.end(), [](const goods& lg, const goods& rg){return lg._price > rg._price; });//对评估进行排序std::sort(list.begin(), list.end(), [](const goods& lg, const goods& rg){return lg._evaluate < rg._evaluate;});std::sort(list.begin(), list.end(), [](const goods& lg, const goods& rg) {return lg._evaluate > rg._evaluate;});return 0;
}

lambda本质上还是一个仿函数,该表达式其实就相当于一个“语法糖”

1.3.3 捕捉列表

lambda表达式中默认只能使用lambda函数体和参数中的变量,如果想使用外层作用域中的变量就需要进行捕捉

  • 捕捉的第一种方法:在捕捉列列表中显示的传值捕捉和引用捕捉捕捉的多个变量用逗号分割

伪代码例:

int a = 1,b = 2,c = 3;
auto add = [a,b,&c]{return a + b + c;}; 
//捕捉列表表示:a和b是值捕捉,&c是引用捕捉

注意:传引用捕捉的变量,若在lambda中被修改了,外部域的也会跟着修改

  • 捕捉的第二种方法:隐式捕捉,[=],表示隐式捕捉;[&],表示隐式引用捕捉,这样我们在lambda表达式中用了哪些变量,编译器就会自动捕捉

伪代码例:

int a = 1,b = 2,c = 3;
auto add = [=]{return a + b + c;}; 
auto func=[&]{a++;b--; return a+b+c;};

注意:lambda表达式中用了哪些变量,编译器就会去自动捕捉哪些变量,没有用到的就不会去捕捉

  • 捕捉的第三种方法:混合使用隐式捕捉和显示捕捉

伪代码例:

int a = 1,b = 2,c = 3,d = 4;
auto function1 = [=,&d]{d++;return a + d;}; //表示其他变量隐式捕捉,d显示引用捕捉
auto function2 = [&,a,b]{c++;return a + b;}; // 表示其他变量隐式引用捕捉,a和b是显示值捕捉

注意:当混合使用时,第一个元素必须是=或者&,并且第一个元素为&混合捕捉时,后面的捕捉必须为值捕捉,同理第一个元素为=混合捕捉时,后面的捕捉必须为引用捕捉

注意:局部的静态变量和全局变量不能捕捉,也不需要捕捉,直接就可以使用

1.3.4 mutable语法

lambda表达式中,传值捕捉本质上是一种拷贝,并且被const修饰所以不能被修改,但可以用mutable关键字来使值捕捉的变量在lambda表达式中被修改,但被修改的变量不会影响外部域的变量,因为它是一种拷贝

代码例:

int main()
{int a = 1, b = 2, c = 3;auto func = [=]()mutable {a++; b++; return a+b+c;};std::cout << func() << std::endl;std::cout << "a:" << a << " " << "b:" << b << " " << "c:" << c << std::endl;return 0;
}

在这里插入图片描述
可以看到外部域的变量并没有被修改

1.3.5 lambda的原理

lambda底层是仿函数对象,当写了一个lambda以后,编译器会自动生成一个对应的仿函数的类。仿函数的类型名是编译器按一定规则生成的,保证不同的lambda生成的类型名不同,lambda参数/返回类型/函数体就是仿函数operator的参数/返回类型/函数体,它的捕捉列表本质是生成的仿函数类的成员变量,也就是说捕捉列表的变量都是lambda类构造函数的实参,若是隐式捕捉,编译器要看使用哪些就传哪些变量.

http://www.whsansanxincailiao.cn/news/30239040.html

相关文章:

  • 电商网站首页布局/永久不收费免费的聊天软件
  • 电子元器件网站怎么做/顺德搜索seo网络推广
  • 给网站做解答是干嘛的/百度关键词排名原理
  • wordpress设置上传文件大小限制/兰州网络推广优化服务
  • 方城微网站开发/培训网站官网
  • 如何在国外网站做免费推广/百度网站关键词排名查询
  • 建设部网站 技术规范/推广普通话标语
  • 做文化传播公司网站/长沙seo网站优化
  • 网站首页像素/google store
  • 男女插孔做暖暖网站大全/软文云
  • 自助建站系统是怎么实现/连接交换
  • html 创意网站/个人网站建设
  • 网站建设用什么软件做/谷歌 google
  • 做热点链接的网站/长沙网站seo技术厂家
  • 做抽奖网站合法吗/百度搜索大数据
  • 没有网站没有推广如何做外贸/武汉seo系统
  • 服装箱包网站建设/怎么做网站推广和宣传
  • 吴江企业建设网站/域名注册入口
  • 阿里云云服务器ecs做网站访问慢/咖啡seo是什么意思
  • linux建设视频网站/公司网站域名续费一年多少钱
  • 中国建设监理工程协会网站/自己做seo网站推广
  • 做网站或者app/海外广告投放公司
  • 什么网站教做医学实验报告/微信小程序开发工具
  • 美团网站网站建设发展/天堂网长尾关键词挖掘网站
  • 网站开发知识产权/关键词优化排名软件案例
  • 手机网站有什么区别吗/百度平台我的订单
  • 网站创建需要多少钱/怎么做一个网站页面
  • 重庆做营销网站建设/免费入驻的卖货平台有哪些
  • 个人做盈利慈善网站/百度账号怎么注册
  • 邢台规划局网站建设/杭州seo网站排名