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

企业网站实名制网络营销师资格证报名

企业网站实名制,网络营销师资格证报名,前端和后端适合什么人,长春财经学院招生简章C11 一、可变参数模板1. 递归函数方式展开参数包2. 逗号表达式展开参数包3. STL容器中的 empalce 相关接口函数 二、lambda 表达式1. C98 中的一个例子2. 使用 lambda 表达式3. lambda 表达式语法#xff08;1#xff09;lambda 表达式各部分说明#xff08;2#xff09;捕… C11 一、可变参数模板1. 递归函数方式展开参数包2. 逗号表达式展开参数包3. STL容器中的 empalce 相关接口函数 二、lambda 表达式1. C98 中的一个例子2. 使用 lambda 表达式3. lambda 表达式语法1lambda 表达式各部分说明2捕获列表说明 4. 函数对象与 lambda 表达式 三、包装器1. function 包装器2. bind 一、可变参数模板 C11 的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板相比 C98/03 类模版和函数模版中只能含固定数量的模版参数可变模版参数是一个巨大的改进。然而由于可变模版参数比较抽象使用起来需要一定的技巧所以这块还是比较晦涩的。所以我们只需要掌握一些基础的可变参数模板特性够了如果大家有需要再可以深入去学习。 其实我们早就接触过可变参数了例如 printf 函数这个是函数的可变参数如下图 … 代表可以传任意个参数。 以下是可变参数模板的语法 // Args是一个模板参数包args是一个函数形参参数包// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。template class ...Argsvoid ShowList(Args... args){}我们可以像以下这样传参 int main(){ShowList(1, 2, 3, 4, 5);ShowList(1, abcde, 3.33);return 0;}我们可以通过 sizeof...(args) 计算出参数包的个数如下 template class ...Argsvoid ShowList(Args... args){cout sizeof...(args) endl;}如果我们想打印参数包中的内容呢我们无法直接获取参数包 args 中的每个参数的只能通过展开参数包的方式来获取参数包中的每个参数这是使用可变模版参数的一个主要特点也是最大的难点即如何展开可变模版参数。由于语法不支持使用 args[i] 这样方式获取可变参数所以我们的用一些其他方式来一一获取参数包的值。 1. 递归函数方式展开参数包 如以下代码 // 递归终止函数void _ShowList(){cout endl;}// 展开函数template class T, class ...Argsvoid _ShowList(const T val, Args... args){cout val ;_ShowList(args...);}template class ...Argsvoid ShowList(Args... args){_ShowList(args...);}int main(){ShowList(1, 2, 3, 4, 5);ShowList(1, abcde, 3.33);return 0;}如上代码我们就可以打印出参数包的内容这种方法叫做编译时的递归推演。 2. 逗号表达式展开参数包 这种展开参数包的方式不需要通过递归终止函数是直接在expand函数体中展开的, PrintArg 不是一个递归终止函数只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。 如下代码 template class Tint PrintArg(T t){cout t ;return 0;}//展开函数template class ...Argsvoid ShowList(Args... args){int arr[] { PrintArg(args)... };cout endl;}上述代码中要初始化 arr就强行让编译器解析参数包参数包有几个参数PrintArg 就依次推演生成几个参数。 3. STL容器中的 empalce 相关接口函数 C11中为容器新增了一些 empalce 的插入接口首先我们看到的 emplace 系列的接口支持模板的可变参数并且万能引用。那么相对 insert 和 emplace 系列接口的优势到底在哪里呢 我们先尝试一下使用两种方法插入一些数据如下 int main(){listYoung::string lt;Young::string s1(abcde);lt.push_back(s1);lt.push_back(move(s1));Young::string s2(edcba);lt.emplace_back(s2);lt.emplace_back(move(s2));return 0;}但是我们发现在这种情况下两者并没有明显的区别那么它们的区别到底在哪呢 下面我们换一种初始化方式我们在构造函数中也打印相应的语句这样有利于我们观察 int main(){listYoung::string lt;lt.push_back(abcde);lt.emplace_back(abcde);return 0;}结果如下 其中 push_back 调的是构造和移动构造emplace_back 只调了构造这是为什么呢原因如下图所示 下面我们再看一种场景多参数传参 int main(){listpairYoung::string, int lt;lt.push_back(make_pair(abcde, 1));cout endl;lt.emplace_back(edcba, 2);return 0;}其原因也与上述的类似 下面我们更改一下我们自己实现的 list 类增加 emplace_back 版本的插入为了方便演示上述过程 首先增加构造节点的构造函数 template class... Argslist_node(Args... args): _data(args...), _next(nullptr), _prev(nullptr){}再增加 emplace_back 的插入版本这里没有实现后面链接的部分代码只是为了演示这个过程 template class... Argsvoid emplace_back(Args... args){Node* newnode new Node(args...);// 链接节点// ...}emplace_back 版本的插入过程如下图所示 结论emplace_back 比 push_back 略微高效一点点并没有很大的提升因为移动构造的成本也是足够低的 二、lambda 表达式 1. C98 中的一个例子 在 C98 中如果想要对一个数据集合中的元素进行排序可以使用std::sort 方法 int main(){int array[] { 4,1,8,5,3,7,0,9,2,6 };// 默认按照小于比较排出来结果是升序std::sort(array, array sizeof(array) / sizeof(array[0]));// 如果需要降序需要改变元素的比较规则std::sort(array, array sizeof(array) / sizeof(array[0]), greaterint());return 0;}如果待排序元素为自定义类型如下 struct Goods{string _name; // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate): _name(str), _price(price), _evaluate(evaluate){}};需要用户定义排序时的比较规则所以这时候需要写仿函数 struct ComparePriceLess{bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;}};struct ComparePriceGreater{bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;}};其中sort 中的 Compare comp 是一个可调用对象 随着 C 语法的发展人们开始觉得上面的写法太复杂了每次为了实现一个 algorithm 算法都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名这些都给编程者带来了极大的不便。因此在 C11 语法中出现了 lambda 表达式。 2. 使用 lambda 表达式 我们可以先见识一下如何使用 lambda 表达式如果想使用 lambda 表达式达到上面的比较效果假设我们需要分别写一个按照商品的价格的高低的排序如下 int main(){vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2,3 }, { 菠萝, 1.5, 4 } };// lambda 表达式sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) {return g1._price g2._price; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2) {return g1._price g2._price; });return 0;}上述代码就是使用 C11 中的 lambda 表达式来解决可以看出 lambda 表达式实际是一个匿名函数。 3. lambda 表达式语法 lambda 表达式书写格式[capture-list] (parameters) mutable - return-type { statement }; 1lambda 表达式各部分说明 [capture-list] : 捕捉列表该列表总是出现在 lambda 函数的开始位置编译器根据[]来判断接下来的代码是否为 lambda 函数捕捉列表能够捕捉上下文中的变量供 lambda 函数使用。 (parameters)参数列表。与普通函数的参数列表一致如果不需要参数传递则可以连同()一起省略 mutable默认情况下lambda 函数总是一个 const 函数mutable 可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。现阶段我们按照默认的使用即可可省略。 -returntype返回值类型。用追踪返回类型形式声明函数的返回值类型没有返回值时此部分可省略。返回值类型明确情况下也可省略由编译器对返回类型进行推导。 {statement}函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获到的变量。 其中捕捉列表和函数体是必须写的其它的可省略。 注意在 lambda 函数定义中参数列表和返回值类型都是可选部分而捕捉列表和函数体可以为空。因此 C11 中最简单的 lambda 函数为[]{}; 该 lambda 函数不能做任何事情。 由于 lambda 表达式是一个可调用对象所以也可以像下面一样写 int main(){auto f1 [](int x) {cout x endl; return 0; };f1(10);return 0;}我们也可以查看一下 lambda 表达式的类型 如上图我们可以看到lambda 表达式的类型是一个类这个类的名称是 lambda uuid. 每个 lambda 都会生成一个类。 2捕获列表说明 捕捉列表描述了上下文中哪些数据可以被 lambda 使用以及使用的方式传值还是传引用。 [var]表示值传递方式捕捉变量 var[]表示值传递方式捕获所有父作用域中的变量(包括this)[var]表示引用传递捕捉变量 var[]表示引用传递捕捉所有父作用域中的变量(包括this)[this]表示值传递方式捕捉当前的 this 指针 注意 父作用域指包含 lambda 函数的语句块语法上捕捉列表可由多个捕捉项组成并以逗号分割。 比如 [, a, b]以引用传递的方式捕捉变量 a 和 b值传递方式捕捉其他所有变量 [a, this]值传递方式捕捉变量 a 和 this引用方式捕捉其他变量捕捉列表不允许变量重复传递否则就会导致编译错误。 比如[, a]已经以值传递方式捕捉了所有变量捕捉 a 重复在块作用域以外的 lambda 函数捕捉列表必须为空在块作用域中的 lambda 函数仅能捕捉父作用域中局部变量捕捉任何非此作用域或者非局部变量都会导致编译报错lambda 表达式之间不能相互赋值即使看起来类型相同。 4. 函数对象与 lambda 表达式 函数对象又称为仿函数即可以像函数一样使用的对象就是在类中重载了 operator() 运算符的类对象。 如下分别为仿函数和 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.49;Rate r1(rate);r1(10000, 2);// lambdaauto r2 [](double monty, int year) {return monty * rate * year; };r2(10000, 2);return 0;}从使用方式上来看函数对象与 lambda 表达式完全一样。 函数对象将 rate 作为其成员变量在定义对象时给出初始值即可lambda 表达式通过捕获列表可以直接将该变量捕获到。 实际在底层编译器对于 lambda 表达式的处理方式完全就是按照函数对象的方式处理的即如果定义了一个 lambda 表达式编译器会自动生成一个类在该类中重载了 operator(). 三、包装器 1. function 包装器 function 包装器 也叫作适配器C 中的 function 本质是一个类模板也是一个包装器。 要学包装器首先需要知道包装器包装的是什么其实包装器包装的是可调用对象目前我们学习到的可调用对象有函数指针、仿函数、lambda我们要学的包装器就是要包装它们三个中的任意一个。 其中函数指针的设计不太好不符合我们常规的写法例如void (*pswap)(int* p1, int* p2)这种方式不好写类型也不好写。 而仿函数类型比较好写但是它比较重它得在全局里面单独定义一个类即使是写一个很简单的比较也是需要定义一个类这种方法太笨重了。 而 lambda 比较灵活但是 lambda 也和函数指针面临同样的问题类型不好写类型是匿名的。 我们先来看看 function 包装器的语法 // 类模板原型如下template class Ret, class... Argsclass functionRet(Args...);模板参数说明Ret: 被调用函数的返回类型Args…被调用函数的形参下面我们来简单使用一下包装器包装可调用对象假设我们需要包装一个实现两个数交换的可调用对象如下先包装函数指针 void swap_func(int x, int y){int tmp x;x y;y tmp;}int main(){int x 10, y 20;cout x x y y endl;// 包装函数指针functionvoid(int, int) f1 swap_func;f1(x, y);cout x x y y endl;return 0;}如上图我们完成对函数指针的包装。 包装函数对象和 lambda int main(){int x 10, y 20;cout x x y y endl;auto swap_lambda [](int r1, int r2){int tmp r1;r1 r2;r2 tmp;};// 包装函数指针functionvoid(int, int) f1 swap_func;f1(x, y);cout x x y y endl;// 包装函数对象functionvoid(int, int) f2 Swap();f2(x, y);cout x x y y endl;// 包装 lambdafunctionvoid(int, int) f3 swap_lambda;f3(x, y);cout x x y y endl;return 0;}但是在实际中我们并不像上面的这样用假设我们需要将可调用对象放入一个容器中假设是 map就可以像下面这样包装 mapstring, functionvoid(int, int) cmdOP {{函数指针, swap_func},{仿函数, Swap()},{lambda, swap_lambda}};我们在使用的时候就像在使用对应的命令去调对应的函数一样这就是回调 int main(){int x 10, y 20;cout x x y y endl endl;auto swap_lambda [](int r1, int r2){int tmp r1;r1 r2;r2 tmp;};mapstring, functionvoid(int, int) cmdOP {{函数指针, swap_func},{仿函数, Swap()},{lambda, swap_lambda}};cmdOP[函数指针](x, y);cout x x y y endl;cmdOP[仿函数](x, y);cout x x y y endl;cmdOP[lambda](x, y);cout x x y y endl;return 0;}2. bind std::bind 函数定义在头文件中是一个函数模板它就像一个函数包装器(适配器)接受一个可调用对象callable object生成一个新的可调用对象来“适应”原对象的参数列表。一般而言我们用它可以把一个原本接收 N 个参数的函数 fn通过绑定一些参数返回一个接收 M 个M 可以大于 N但这么做没什么意义参数的新函数。同时使用 std::bind 函数还可以实现参数顺序调整等操作。 // 原型如下template class Fn, class... Args/* unspecified */ bind (Fn fn, Args... args);// with return type (2) template class Ret, class Fn, class... Args/* unspecified */ bind (Fn fn, Args... args);可以将 bind 函数看作是一个通用的函数适配器它接受一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。 调用 bind 的一般形式auto newCallable bind(callable,arg_list); 其中newCallable 本身是一个可调用对象arg_list 是一个逗号分隔的参数列表对应给定的 callable 的参数。当我们调用 newCallable 时newCallable 会调用 callable并传给它 arg_list 中的参数。 arg_list 中的参数可能包含形如 _n 的名字其中 n 是一个整数这些参数是“占位符”表示 newCallable 的参数它们占据了传递给 newCallable 的参数的 “位置”。数值 n 表示生成的可调用对象中参数的位置_1 为 newCallable 的第一个实参_2 为第二个实参以此类推。 使用举例 int Sub(int a, int b){return a - b;}int main(){functionint(int, int) f1 Sub;cout f1(10, 5) endl;// 调整参数顺序functionint(int, int) f2 bind(Sub, placeholders::_2, placeholders::_1);cout f2(10, 5) endl;return 0;}使用 bind 调整参数顺序如下图所示 还可以像以下这种用法调整参数个数 int main(){functionint(int, int) f1 Sub;cout f1(10, 5) endl;// 调整参数个数有些参数可以使用 bind 时固定functionint(int) f3 bind(Sub, 20, placeholders::_1);cout f3(5) endl;return 0;}下面再看一个场景在类中调用函数指针 假设有个 Plus 类 class Plus{public:static int plusi(int a, int b){return a b;}double plusd(double a, double b){return a b;}};我们需要在类外包装类中的成员函数有以下做法 int main(){// 成员函数取地址比较特殊要加一个类域和functionint(int, int) f1 Plus::plusi;cout f1(1, 2) endl;// 上面静态成员函数没有 this 指针所以不用传指针// 普通成员函数有 this 指针所以需要传对象的指针functiondouble(Plus*, double, double) f2 Plus::plusd;Plus ps;cout f2(ps, 1.1, 2.2) endl;// 这里传 Plus 编译器会进行特殊处理实际上是 Plus*functiondouble(Plus, double, double) f3 Plus::plusd;cout f3(Plus(), 1.11, 2.22) endl;return 0;}如上对于普通成员函数每一次都要传 Plus*这时候我们就可以用上面学的 bind 将这个步骤省去即调整参数的个数如下 functiondouble(double, double) f4 bind(Plus::plusd, Plus(), placeholders::_1, placeholders::_2);cout f4(1.11, 2.22) endl;如上经过 bind 后每次使用可调用对象的时候就不需要传 Plus* 了只需要传参数即可。
http://www.zqtcl.cn/news/194419/

相关文章:

  • 异地备案 网站中信建设有限责任公司经济性质
  • 网站没有备案怎么申请广告宿迁莱布拉网站建设
  • 太原适合网站设计地址网站建设 教学视频教程
  • 建商城网站需要多少钱网站开发维护报价单
  • 唐山网站建设冀icp备婚纱网站页面设计
  • 做购物网站支付需要怎么做手机网站建设教程
  • 国外网站空间租用哪个好建站快车打电话
  • 自媒体网站 程序做药公司的网站前置审批
  • 简洁网站模板素材廊坊建设企业网站
  • 长沙建站找有为太极就治就网站内容如何自动关联新浪微博
  • 手机企业网站设计理念企业建设网站的步骤是什么?
  • 网站建设与管理视频网站推广的方法枫子
  • 苏州市住房和城乡建设局官方网站宠物之家网站开发
  • 建个人网站活字格能开发企业网站吗
  • php网站后台密码忘记做电子商务网站 语言
  • 网站建设策划师怎样进入国外网站
  • 建设银行商城网站浙江建站管理系统价格
  • 我想做个网站怎么做的常用的网络营销方法及效果
  • 南通专业做网站南宁网站建设mxfsem
  • 阿里巴巴电子商务网站建设目的网站专题素材
  • 浙江虎霸建设机械有限公司网站哪个网站做简历好
  • 网站做电商资质吗网站开发作品
  • 大型彩灯制作公司临清聊城网站优化
  • 网站建设灬金手指下拉十五网络运维工程师简历怎么写
  • 黄岛建设局网站动漫采集WordPress
  • 做网站现在挣钱吗wordpress 网址导航主题
  • 外贸网站什么采集wordpress主题更换logo
  • 唐山开发网站的公司长沙营销型网站设计
  • 数据库策略网站推广的有效方法有美辰网站建设
  • c 网站开发构想做网站的点子