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

雄县哪里有建设网站的wordpress订单推送微信

雄县哪里有建设网站的,wordpress订单推送微信,wordpress简码套用,网站做图分辨率文章目录 一、C11简介二、列表初始化二、声明四、范围for循环五、STL中的变化六、右值引用和移动语义1. 什么是左值#xff1f;什么是左值引用#xff1f;2. 左值引用与右值引用比较3. 右值引用使用场景和意义4. 完美转发 新的类功能默认成员函数类成员变量初始化defaultdele… 文章目录 一、C11简介二、列表初始化二、声明四、范围for循环五、STL中的变化六、右值引用和移动语义1. 什么是左值什么是左值引用2. 左值引用与右值引用比较3. 右值引用使用场景和意义4. 完美转发 新的类功能默认成员函数类成员变量初始化defaultdeletefinal与override关键字可变参数模板递归函数方式展开参数包初始化列表展开参数包emplace lambda表达式lambda表达式概念捕获列表说明仿函数/函数对象与lambda表达式 包装器function包装器bind 一、C11简介 1998年是C标准委员会成立的第一年本来计划以后每5年视实际需要更新一次标准C国际标准委员会在研究C 03的下一个版本的时候一开始计划是2007年发布所以最初这个标准叫C07。但是到06年的时候官方觉得2007年肯定完不成C 07而且官方觉得2008年可能也完不成。最后干脆叫C0x。x的意思是不知道到底能在07还是08还是09年完成。结果2010年的时候也没完成最后在2011年终于完成了C标准。所以最终定名为C11。 从C0x到C11C标准10年磨一剑第二个真正意义上的标准珊珊来迟。相比于C98/03C11则带来了数量可观的变化其中包含了约140个新特性以及对C03标准中约600个缺陷的修正这使得C11更像是从C98/03中孕育出的一种新语言。https://en.cppreference.com/w/cpp/11 相比较而言C11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全不仅功能更强大而且能提升程序员的开发效率公司实际项目开发中也用得比较多是C的重点内容。 二、列表初始化 在C98中标准允许使用花括号{ }对数组或者结构体元素进行统一的列表初始值设定。C11扩大了用大括号括起的列表/初始化列表的使用范围使其可用于所有的内置类型和用户自定义的类型使用初始化列表时可添加等号也可不添加。 int main() {int x 1;int y {2};int z {3};//自定义类型也支持列表初始化是调用构造函数Date d1(2023,2,24);// C11支持的列表初始化这里会调用构造函数初始化Date d2 {2023,2,24};Date d2{2023,2,24};return 0; }普通对象用花括号初始化很怪能看懂即可不建议使用。列表初始化真正的作用是给容器初始化如下所示 int main() {vectorint v1 {1,2,3,4};vectorint v2{1,2,3,4};list int lt1{1,2,3,4};list int lt2{1,2,3,4};return 0; }std::initializer_list C11提供了initializer_list类此类型用于访问C初始化列表中的值该列表是const T类型的元素列表。也就是说初始化列表其实是有类型的它的类型就是initializer_listT。 int main() {auto il { 10, 20, 30 };cout typeid(il).name() endl; //class std::initializer_listintreturn 0; }C11将所有的容器都支持了initializer_list这样的构造函数所以可以用容器都列表初始化例如C11支持list (initializer_listvalue_type il这样初始化容器对象就更方便了。同时也可以作为operator的参数这样就可以用大括号赋值。 vectorint v { 1,2,3,4 }; listint lt { 1,2 };// 这里{sort, 排序}会先初始化构造一个pair对象 mapstring, string dict { {sort, 排序}, {insert, 插入} };// 使用大括号对容器赋值 v {10, 20, 30};模拟实现的vector也支持{}初始化和赋值 templateclass T class vector { public:typedef T* iterator;vector(initializer_listT l){_start new T[l.size()];_finish _start l.size();_endofstorage _start l.size();iterator vit _start;typename initializer_listT::iterator lit l.begin();for (auto e : l){*vit e;} }vectorT operator(initializer_listT l) {vectorT tmp(l);std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_endofstorage, tmp._endofstorage);return *this;} private:iterator _start;iterator _finish;iterator _endofstorage; };二、声明 auto 在C98中auto是一个存储类型的说明符表明变量是局部自动存储类型但是局部域中定义局部的变量默认就是自动存储类型所以auto就没什么价值了。C11中废弃auto原来的用法将其用于实现自动类型腿断。这样要求必须进行显示初始化让编译器将定义对象的类型设置为初始化值的类型。 int i 10; auto p i; mapstring, string dict { {a, 1}, {b, 2} }; auto it dict.begin();cout typeid(i).name() endl; //int cout typeid(p).name() endl; //int* cout typeid(it).name() endl; //mapstring, string::iteratordecltype 关键字decltype 将变量的类型声明为表达式指定的类型,与auto的区别auto定义的变量取决于等号右侧而decltype定义的变量取决于等号左侧。 int x 10;decltype(x) y1 20.22; cout typeid(y1).name() endl; //intnullptr 由于C中NULL被定义成字面量0这样就可能回带来一些问题因为0既能指针常量又能表示整形常量。所以出于清晰和安全的角度考虑C11中新增了nullptr用于表示空指针。 四、范围for循环 for (declaration : expression) {// 循环体 }declaration 表示遍历声明在遍历过程中当前被遍历到的元素会被存储到声明的变量中。expression 是要遍历的对象它可以是表达式 、容器、数组、初始化列表等。范围for的底层原理就是被替换为了迭代器实现了迭代器就是实现了范围for。 五、STL中的变化 C11中的一些新容器但是实际最有用的是unordered_map和unordered_set。 array array可以认为是一个静态的顺序表使用上跟数组基本没有差别。因为C语言数组中对于越界的判定抽查存在误差C11希望用户使用array容器来替换数组容器化可以严格检查越界读写因为检查是调用的operator[]去检查。实际上C语言数组已经习惯了并且用array不如用vector因为array在栈上而vector在堆上不用考虑栈溢出所以array很少用。 forward_list forward_list可以认为是一个单链表list是双向链表forward_list可以减少空间如果不是非常特殊的需求实际开发中也不会用forward_list。 容器内部的变化 容器内部都支持了initializer_list构造用来支持列表初始化。增加了cbegin和cend的系列接口实际中也没什么用。增加了移动构造和移动赋值在一定场景下可以提高效率。增加了右值引用参数的插入提高了效率。 六、右值引用和移动语义 传统的C语法中就有引用的语法而C11中新增了的右值引用语法特性无论左值引用还是右值引用都是给对象取别名。 1. 什么是左值什么是左值引用 左值是一个表示数据的表达式左值可以获取它的地址的值。除const修饰符后的左值不能赋值(可以取地址)外其余情况左值可以赋值。 int main() {// 以下的p、b、c、*p都是左值int* p new int(0);int b 1;const int c 2;// 以下几个是对上面左值的左值引用int* rp p;int rb b;const int rc c;int pv *p;return 0; }什么是右值什么是右值引用 右值也是一个表示数据的表达式右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边最重要的是右值不能取地址且不能放到赋值符号的左边。 int main() {double x 1.1, y 2.2;// 以下几个都是常见的右值,不能取地址10;x y;f(x, y);// 以下几个都是对右值的右值引用int rr1 10;double rr2 x y;double rr3 f(x, y);// 不能放到赋值符号的左边// 这里编译会报错error C2106: “”: 左操作数必须为左值10 1;x y 1;f(x, y) 1;return 0; }2. 左值引用与右值引用比较 左值引用 左值引用只能引用左值不能引用右值。但是const左值引用既可引用左值也可引用右值因为右值是不能被改变的的。 templateclass T void Func(const Tx) //x既能接收左值也能接收右值体现了const左值引用引用右值的价值。 {}int main() {// 左值引用只能引用左值不能引用右值。int a 10;int ra1 a; // ra1为a的别名//int ra2 10; // 编译失败因为10是右值// const左值引用既可引用左值也可引用右值。const int ra3 10;const int ra4 a;return 0; }右值引用 右值引用只能右值不能引用左值。但是右值引用可以move以后的左值。 int main() {// 右值引用只能右值不能引用左值。int r1 10;// error C2440: “初始化”: 无法从“int”转换为“int ”, message : 无法将左值绑定到右值引用int a 10;int r2 a;// 右值引用可以引用move以后的左值int r3 std::move(a);return 0; }3. 右值引用使用场景和意义 引用的价值是为了减少拷贝尤其是深拷贝。左值引用做参数和做返回值都可以提高效率但是当函数返回对象是一个局部变量出了函数作用域就不存在了就不能使用左值引用返回只能传值返回传值返回会导致至少1次拷贝构造编译器可能做优化。例如模拟实现的to_string函数只能传值返回进行拷贝构造在屏幕中打印“深拷贝”。 //拷贝构造 string (const strings):str(nullptr) {cout深拷贝endl;string tmp(s._str);swap(tmp); }Jared::string to_string(int value) {Jared::string str;////return str; } int main() {Jared::string ret1 Jared::to_string(1234);return 0; }右值引用的出现使得C增加了两个函数移动构造和移动赋值可以解决上述问题。如果一个需要深拷贝的类实现了移动构造和移动赋值就不怕传值返回的情况了。 移动构造 // 移动构造 string(string s):_str(nullptr),_size(0),_capacity(0) {cout string(string s) -- 资源转移 endl;swap(s); }将引动构造加入到类中再运行上面Jared::to_string的调用这里没有调用深拷贝的拷贝构造而是调用了移动构造在屏幕中打印资源转移。移动构造中没有新开空间拷贝数据所以效率提高了。C11将右值进行了划分内置类型的右值称为纯右值自定义类型的右值称将亡值。执行return str的时候str被识别编译器识别返回值类型来调用拷贝构造或移动构造 为将亡值右值)从而调用移动构造。Jared::string ret1 Jared::to_string(1234); 在这里又是一次移动构造将将亡值赋值给ret1但是编译器优化后变为以此移动构造。 移动构造本质是将参数右值的资源窃取过来占位已有那么就不用做深拷贝了所以它叫做移动构造就是窃取别人的资源来构造自己。 移动赋值 // 移动赋值 string operator(string s) {cout string operator(string s) -- 移动语义 endl;swap(s);return *this; }int main() {Jared::string ret1;ret1 Jared::to_string(1234); //不仅拿到了1234资源还把自己的资源还给将亡值当它带走return 0; }可以看到调用了一次移动构造和一次移动赋值。Jared::to_string函数中会先用str生成构造生成一个临时对象但是编译器很聪明的在这里把str识别成了右值调用了移动构造。然后把这个临时对象做为Jared::to_string函数调用的返回值赋值给ret1这里调用的移动赋值。 STL容器插入接口函数也增加了右值引用版本 通常插入的函数接口在C11后都支持右值版本插入的过程中如果传递的是右值对象那么就进行资源转移从而减少拷贝。 int main() {listbit::string lt;Jared::string s1(1111);// 这里调用的是拷贝构造lt.push_back(s1);// 下面调用都是移动构造lt.push_back(2222);lt.push_back(std::move(s1));return 0; }std::move()函数 当需要用右值引用引用一个左值时可以通过move函数将左值转化为右值。C11中std::move()函数位于头文件中该函数名字具有迷惑性它并不搬移任何东西唯一的功能就是将一个左值强制转化为右值引用然后实现移动语义。 int main() {Jared::string s1(hello world);// 这里s1是左值调用的是拷贝构造Jared::string s2(s1);// 这里我们把s1 move处理以后, 会被当成右值调用移动构造// 但是这里要注意一般是不要这样用的因为我们会发现s1的// 资源被转移给了s3s1被置空了。Jared::string s3(std::move(s1));return 0; }4. 完美转发 模板中的万能引用 void Fun(int x){ cout 左值引用 endl; } void Fun(const int x){ cout const 左值引用 endl; } void Fun(int x){ cout 右值引用 endl; } void Fun(const int x){ cout const 右值引用 endl; }// std::forwardT(t)在传参的过程中保持了t的原生类型属性。 templatetypename T void PerfectForward(T t) {Fun(std::forwardT(t)); }在模板中比较特殊(属于语法特性)T t既可以引用左值也可以引用右值被称为万能引用。也被称为语法折叠传左值就是左值引用传右值就是右值引用。 int main() {PerfectForward(10); // 右值int a;PerfectForward(a); // 左值PerfectForward(std::move(a)); // 右值const int b 8;PerfectForward(b); // const 左值PerfectForward(std::move(b)); // const 右值return 0; }如果不用std::forward(t)输出的结果都是左值引用/const左值引用t全被被看为左值。而使用std::forward(t) 可以保证在传参的过程中保持了t的原生类型属性。 新的类功能 默认成员函数 C11 新增了两个默认成员函数移动构造函数和移动赋值运算符重载。 如果没有实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动构造如果实现了就调用移动构造没有实现就调用拷贝构造。默认移动赋值跟上面移动构造完全类似。如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值。拷贝对象需要深拷贝的时候需要自己写移动构造和移动赋值(大多数情况)比如string、vector、list。 类成员变量初始化 C11允许在类定义时给成员变量初始缺省值默认生成构造函数会使用这些缺省值初始化。 default default关键字会强制生成默认函数的关键字假设你要使用某个默认的函数但是因为一些原因这个函数没有默认生成。比如我们提供了拷贝构造就不会生成默认的构造函数了那么我们可以使用default关键字显示指定构造生成。 class Person { public:Person() default; Person(const Person p):_name(p._name),_age(p._age){} private:bit::string _name;int _age; };delete 如果能想要限制某些默认函数的生成在C98中是该函数设置成private这样只要其他人想要调用就会报错。在C11中更简单只需在该函数声明加上delete即可该语法指示编译器不生成对应函数的默认版本称delete修饰的函数为删除函数。例如不想让person对象拷贝使用delete限制拷贝构造函数的生成。 class Person { public:Person(const char* name , int age 0):_name(name), _age(age){}Person(const Person p) delete; private:bit::string _name;int _age; };final与override关键字 final与override关键字在继承和多态章节已经进行了详细讲解。 可变参数模板 C11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板相比C98/03类模版和函数模版中只能含固定数量的模版参数可变模版参数无疑是一个巨大的改进。 案例 // Args是一个模板参数包args是一个函数形参参数包 // 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。 template class ...Args void ShowList(Args... args) {}上面的参数args前面有省略号所以它就是一个可变模版参数把带省略号的参数称为“参数包”它里面包含了0到NN0个模版参数。语法不支持使用args[i]这样方式获取可变参数也就是无法直接获取参数包args中的每个参数只能通过展开参数包的方式来获取参数包中的每个参数这是使用可变模版参数的一个主要特点也是最大的难点即如何展开可变模版参数。 template class ...Args void ShowList(Args... args) {//sizeof...(args)可以帮我们获取参数包的参数个数coutsizeof...(args)endl; } int main() {ShowList();ShowList(1);ShowList(1,A,acd);return 0; }递归函数方式展开参数包 // 递归终止函数 template class T void ShowList() {cout endl; } // 展开函数 template class T, class ...Args void ShowList(const T value, Args... args) {cout value ;ShowList(args...); }初始化列表展开参数包 这种展开参数包的方式不需要通过递归终止函数是直接在函数体中展开的这种就地展开参数包的方式实现的关键是初始化列表通过初始化列表来初始化一个变长数组。在构造int数组的过程中就将参数包{printarg(args)…}会展开成(printarg(arg1)),(printarg(arg2)), (printarg(arg3))…这个数组的目的纯粹是为了在数组构造的过程展开参数包。 template class T int PrintArg(T t) {cout t ;return 0; } // 展开函数 template class... Args void ShowList(Args... args) {int arr[] {PrintArg(args)...};cout endl; }emplace C中emplace系列的接口支持模板的可变参数并且万能引用。 int main() {std::list std::pairint, char mylist;// emplace_back支持可变参数拿到构建pair对象的参数后自己去创建对象// 那么在这里我们可以看到除了用法上和push_back没什么太大的区别mylist.emplace_back(10, a);mylist.emplace_back(20, b);mylist.emplace_back(make_pair(30, c));mylist.push_back(make_pair(40, d));mylist.push_back({ 50, e });for (auto e : mylist)cout e.first : e.second endl;return 0; }pushback是构造拷贝构造左值/移动构造右值。emplace_back支持可变参数直接构造。效率稍微高一些但是pushback支持移动构造后差别也不是很大。 lambda表达式 lambda表达式也叫做匿名函数。之前提到的函数指针、仿函数/函数对象是能像函数一样使用的对象lambda表达式也可以同样做到。 在C98中如果想要对一个数据集合中的元素进行排序可以使用std::sort方法。 #include algorithm #include functional int main() {int array[] {4,1,8,5,3,7,0,9,2,6};// 默认按照小于比较排出来结果是升序std::sort(array, arraysizeof(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;} }; int main() {vectorGoods v {{苹果, 2.1, 5}, {香蕉, 3, 4}, {橙子, 2.2, 3}, {菠萝, 1.5, 4}};sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater()); }随着C语法的发展人们开始觉得上面的写法太复杂了每次为了实现一个algorithm算法都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名这些都给编程者带来了极大的不便。因此在C11语法中出现了Lambda表达式。 lambda表达式概念 int main() {vectorGoods v {{苹果, 2.1, 5}, {香蕉, 3, 4}, {橙子, 2.2, 3}, {菠萝, 1.5, 4}};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; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){ return g1._evaluate g2._evaluate; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){ return g1._evaluate g2._evaluate; }); }上述代码就是使用C11中的lambda表达式来解决可以看出lambda表达式实际是一个匿名函数。 lambda表达式书写格式[capture-list] (parameters) mutable - return-type {statement}[capture-list] : 捕捉列表该列表总是出现在lambda函数的开始位置编译器根据[]来判断接下来的代码是否为lambda函数捕捉列表能够捕捉上下文中的变量供lambda函数使用。 (parameters)参数列表。与普通函数的参数列表一致如果不需要参数传递则可以连同()一起省略。 mutable默认情况下lambda函数总是一个const函数mutable可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。 -returntype返回值类型。用追踪返回类型形式声明函数的返回值类型没有返回值时此部分可省略。返回值类型明确情况下也可省略由编译器对返回类型进行推导。 {statement}函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获到的变量。 在lambda函数定义中参数列表和返回值类型都是可省略部分而捕捉列表和函数体可以为空。因此C11中最简单的lambda函数为[]{}; 该lambda函数不能做任何事情。 案例 int main() {// 两数相加的lambdaauto add1 [](int a, int b) - int{ return a b; };cout add1(1, 2) endl;// 交换变量的lambdaint x 0;int y 1;auto swap1 [](intx1,intx2){int tmpx1;x1x2;x2tmp;};swap1(x,y);// 不传参数交换xy的lambda----捕捉列表// 但是默认捕捉过来的变量不能修改可以加mutale修改变量// 但是是传值捕捉实参不会改变auto swap2 [x,y]()mutable{int tmpx;yx;xtmp;}; }通过上述例子可以看出lambda表达式实际上可以理解为匿名函数该函数无法直接调用如果想要直接调用可借助auto将其赋值给一个变量。 捕获列表说明 捕捉列表描述了上下文中那些数据可以被lambda使用以及使用的方式传值还是传引用。 [var]表示值传递方式捕捉变量var[]表示值传递方式捕获所有父作用域中的变量(包括this)[var]表示引用传递捕捉变量var[]表示引用传递捕捉所有父作用域中的变量(包括this)[this]表示值传递方式捕捉当前的this指针 注意事项 a. 父作用域指包含lambda函数的语句的当前栈帧。 b. 语法上捕捉列表可由多个捕捉项组成并以逗号分割。 比如[, a, b]以引用传递的方式捕捉变量a和b值传递方式捕捉其他所有变量 c. 捕捉列表不允许变量重复传递否则就会导致编译错误。 比如[, a]已经以值传递方式捕捉了所有变量捕捉a重复 d. 在块作用域以外的lambda函数捕捉列表必须为空。 e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量或者全局变量。 f. lambda表达式之间不能相互赋值即使看起来类型相同。 仿函数/函数对象与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);// lamberauto r2 [](double monty, int year) - double{return monty * rate * year;};r2(10000, 2);return 0; }函数对象/又称为仿函数即可以想函数一样使用的对象就是在类中重载了operator()运算符的类对象。从使用方式上来看函数对象与lambda表达式完全一样。函数对象将rate作为其成员变量在定义对象时给出初始值即可lambda表达式通过捕获列表可以直接将该变量捕获到。 包装器 function包装器 function包装器也叫作适配器。C中的function本质是一个类模板也是一个包装器。通过下面的程序验证我们会发现useF函数模板实例化了三份因为打印出来的count都是1并且地址也都不相同会导致模板的效率低下。 // useF可能是函数指针、函数对象(仿函数对象)、是lamber表达式对象 // 所以这些都是可调用的类型如此丰富的类型可能会导致模板的效率低下 template class F, class T T useF(F f, T x) {static int count 0;cout count: count endl;cout count: count endl;return f(x); } double f(double i) {return i / 2; } struct Functor {double operator()(double d){return d / 3;} };int main() {// 函数名cout useF(f, 11.11) endl;// 函数对象cout useF(Functor(), 11.11) endl;// lamber表达式cout useF([](double d) - double{ return d / 4; },11.11) endl;return 0; }头文件functional// 类模板原型如下 template class T function; template class Ret, class... Args class functionRet(Args...); 模板参数说明Ret: 被调用函数的返回类型Args…被调用函数的形参#include functional template class F, class T T useF(F f, T x) {static int count 0;cout count: count endl;cout count: count endl;return f(x); } double f(double i) {return i / 2; } struct Functor {double operator()(double d){return d / 3;} }; int main() {// 函数名std::functiondouble(double) func1 f;cout useF(func1, 11.11) endl;// 函数对象std::functiondouble(double) func2 Functor();cout useF(func2, 11.11) endl;// lamber表达式std::functiondouble(double) func3 [](double d) - double{ return d / 4; };cout useF(func3, 11.11) endl;return 0; }包装器可以很好的解决该的问题此时模板就不会实例化三份useF函数而打印的count地址都是同一个。由于函数调用可以使用函数名、函数指针、函数对象或有名称的lambda表达式可调用类型太丰富导致模板的效率极低而包装器使用统一的方式保存一个可调用对象用于解决函数调用效率低的问题。 但是注意类的成员函数静态成员函数除外在在使用包装器的时候要传递类型等号右边要使用引用。 例如 // 函数名(函数指针) std::functionint(int, int) func1 f; cout func1(1, 2) endl; // 函数对象/仿函数 std::functionint(int, int) func2 Functor(); cout func2(1, 2) endl; // lamber表达式 std::functionint(int, int) func3 [](const int a, const int b) {return a b; }; cout func3(1, 2) endl; // 类的成员函数 std::functiondouble(Plus, double, double) func4 Plus::plusd; cout func4(Plus(), 1.1, 2.2) endl;包装器的其他一些场景 class Solution { public:int evalRPN(vectorstring tokens){stackint st;mapstring, functionint(int, int) opFuncMap {{, [](int i, int j){ return i j; }},{-, [](int i, int j){ return i - j; }},{*, [](int i, int j){ return i * j; }},{/, [](int i, int j){ return i / j; }}};for (auto str : tokens){if (opFuncMap.find(str) ! opFuncMap.end()){int right st.top();st.pop();int left st.top();st.pop();st.push(opFuncMap[str](left, right));}else{st.push(stoi(str));}}return st.top();} };bind std::bind函数定义在头文件中是一个函数模板它就像一个函数包装器接受一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。一般而言用它可以把一个原本接收N个参数的函数fn通过绑定一些参数返回一个接收M个参数的新函数。同时使用std::bind函数还可以实现参数顺序调整等操作。 // 原型如下 template class Fn, class... Args /* unspecified */ bind (Fn fn, Args... args); 案例 表示绑定函数plus 参数分别由调用 func1 的第一二个参数指定 std::functionint(int, int) func1 std::bind(Plus, placeholders::_1, placeholders::_2);应用 绑定死固定的参数 #include functional int Plus(int a, int b) {return a b; } class Sub { public:int sub(int a, int b){return a - b;} };int main() {functionint(int,int) funPlus Plus;functionint(Sub,int,int) funSub Sub::sub;mapstring,functionint(int,int) funcMap{{,funPlus},{-,funSub }};return 0; }在该情况中使用map传的时候需要传入两个参数传-的时候需要传入三个参数这就导致无法正确使用map主要是不知道传几个参数合适。此时就需要绑定绑定了第一个参数此时只需要在传两个参数即可这是就可以方便的使用map了。 int main() {functionint(int,int) funPlus Plus;//functionint(Sub,int,int) funSub Sub::sub;functionint(int,int) funSub bind(Sub::sub,Sub(),placeholders::_1,placeholders::_2);mapstring,functionint(int,int) funcMap{{,funPlus},//{-,funSub}{-,funSub}};return 0; }参数调整顺序 std::functionint(int, int) func4 std::bind(Sub::sub, s, placeholders::_2, placeholders::_1); cout func3(1, 2) endl; cout func4(1, 2) endl;
http://www.hkea.cn/news/14387832/

相关文章:

  • 如何给网站续费网站建设着
  • 有域名后怎么建网站中关村在线网站的建设
  • 怎么用自己的网站做邮箱产品设计出来好找工作吗
  • 博客网站排名大全番禺广州网站建设
  • 企业网站建立流程的第一步是做软件赚钱吗
  • 域名如何绑定网站pc 移动网站 模板
  • 广州做网站公司哪家好腾讯云wordpress插件下载
  • 中国建设招标信息网站开网店详细步骤
  • 网站策划的知识网站开发网上悼念
  • 深圳做网站乐云seo598做二手设备的网站
  • 网站建设与网页设计制作wordpress代码缩进
  • idc销售网站php源码建立网站的详细步骤知乎
  • 个人网站开发公司seo网站架构设计
  • 山东住房城乡建设部网站洛阳东翔科技做的网站
  • 自学织梦做网站要多久dw做购物网站
  • 网站模板源码仿京东网站模板
  • 青岛网站设计案例wordpress 主机和域名绑定
  • 找人建个网站多少钱杭州网站建设网
  • 软件下载大全网站无锡网站建设首选捷搜
  • 外贸网站建设推广培训洛阳网站建设的公司哪家好
  • 宝贝做网站甘肃省城乡住房建设厅网站首页
  • 专业网站改版网站建设咨
  • 江西省网站建设腾讯企点网页版
  • 网络管理系统的组成西安seo网站关键词
  • 安徽省建设厅人员名单官方网站网站开发者工具的网络选项
  • 响应式网站设计公司wordpress 主题字号
  • 个人网站上传有啥要求网站建设报告家教总结
  • 沈阳网站建设优秀公司小程序跳转网页方法
  • 网站建设 翰臣科技襄阳宜城网站建设
  • 湘潭网站建设磐石网络建设银行网站-个人业务