经验范围 网站建设,黑帽友情链接,做a动漫视频在线观看网站,江西网站开发哪家好目录
引言
一. 新的类功能
1.1 默认的移动构造和移动赋值
1.2 成员变量声明时给缺省值
1.3 default与delete
1.4 final与override
1.5 委托构造函数
1.6 继承构造函数
二. STL中的一些变化
三. lambda
3.1 lambda表达式语法
3.2 捕捉列表
3.3 lambda的应用
3.4 l…目录引言一. 新的类功能1.1 默认的移动构造和移动赋值1.2 成员变量声明时给缺省值1.3 default与delete1.4 final与override1.5 委托构造函数1.6 继承构造函数二. STL中的一些变化三. lambda3.1 lambda表达式语法3.2 捕捉列表3.3 lambda的应用3.4 lambda的原理四. 包装器4.1 function4.2 bind总结引言C11 是现代 C 的奠基版本它不仅补齐了长期存在的语言缺陷还为泛型编程、对象语义管理、高性能编程等领域提供了全新的抽象方式。无论你是进行底层系统开发、构建高性能服务器还是实现通用库组件C11 都是绕不开的一道坎。一. 新的类功能1.1 默认的移动构造和移动赋值原来C类中有6个默认成员函数构造函数/析构函数/拷贝构造函数/拷贝赋值重载/取地址重 载/const 取地址重载最后重要的是前4个后两个用处不大默认成员函数就是我们不写编译器 会生成一个默认的。C11 新增了两个默认成员函数移动构造函数和移动赋值运算符重载。如果你没有自己实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一 个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动构造如果实现了就调用移动构造没有实现就调用拷贝构造。如果你没有自己实现移动赋值重载函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意 一个那么编译器会自动生成一个默认移动赋值。默认生成的移动赋值重载函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动赋值如果实现了就调用移动赋值没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值。class Person { public: Person(const char* name 张三, int age 19) :_name(name) , _age(age) { } /*Person(const Person p) :_name(p._name) ,_age(p._age) {}*/ /*Person operator(const Person p) { if(this ! p) { _name p._name; _age p._age; } return *this; }*/ /*~Person() {}*/ private: bit::string _name; int _age; }; int main() { Person s1; Person s2 s1; Person s3 std::move(s1); Person s4(xxx, 1); s4 std::move(s2); return 0; }1.2 成员变量声明时给缺省值在最开始类和对象中已经奖结果讲解过如果遗忘点击复习【C】类和对象1.3 default与deleteC11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数但是因为一些原因 这个函数没有默认生成。比如我们提供了拷贝构造就不会生成移动构造了那么我们可以使用 default关键字显示指定移动构造生成。如果能想要限制某些默认函数的生成在C98中是该函数设置成private并且只声明补丁已 这样只要其他人想要调用就会报错。在C11中更简单只需在该函数声明加上delete即可该语法指示编译器不生成对应函数的默认版本称delete修饰的函数为删除函数。class Person { public: Person(const char* name 张三, int age 19) :_name(name) , _age(age) { } // default解决 “自定义某个函数后默认函数消失” 的问题 // 注意在VS中这三个如果要生成就要一起生成 //Person(const Person p) default; //Person(Person p) default; //Person operator(const Person p) default; // 一些类不期望被拷贝 // C11 //Person(const Person p) delete; ~Person() {} private: // C98只声明(声明为私有)不实现 //Person(const Person p); bit::string _name; int _age; }; int main() { Person s1; Person s2 s1; Person s3 std::move(s1); Person s4(xxx, 1); s4 std::move(s2); return 0; }1.4 final与override在之前已经讲解过如果遗忘点击复习【C】多态1.5 委托构造函数C中的委托构造函数Delegating Constructor是C11引入的特性允许一个构造函数调用同类中的其他构造函数从而减少代码重复并提高可维护性。被委托的构造函数必须初始化所有成员变量因为委托构造函数后不能再重复初始化。class Example { public: Example(int a, int b) :_x(a) , _y(b) { cout 目标构造函数\n; } Example(int a) : Example(a, 0) { cout 委托构造函数\n; } int _x; int _y; }; class Time { public: // 所有参数都会走初始化列表虽然这里没有写second但是second也会走这里的初始化列表初始化 // 初始化所有成员 Time(int h, int m) :_hour(h) , _minute(m) {} // error C3511: “Time”: 对委托构造函数的调用应仅为成员初始值设定项 // error C2437 : “_second”: 已初始化 Time(int h, int m, int s) :Time(h, m) // , _second(s) {} private: int _hour; int _minute; int _second 0; }; int main() { Example(1, 2); Example(1); return 0; }1.6 继承构造函数继承构造函数是C11引入的一项特性它允许派生类直接继承基类的构造函数而不需要手动重新定义它们。这一特性显著简化了派生类的编写特别是在基类有多个构造函数的情况下。派生类继承基类的普通构造函数特殊的拷贝构造函数/移动构造函数不继承。继承构造函数中派生类自己的成员变量如果有缺省值会使用缺省值初始化如果没有缺省值那么跟之前类似内置类型成员不确定自定义类型成员使用默认构造初始化。class Base { public: Base(int x, double d) :_x(x) , _d(d) {} Base(int x) :_x(x) {} Base(double d) :_x(d) {} protected: int _x 0; double _d 0; }; // 传统的派生类实现构造 //class Derived : public Base { //public: // Derived(int x) : Base(x) {} // Derived(double d) : Base(d) {} // Derived(int x, double d) : Base(x, d) {} //}; // C11继承基类的所有构造函数 class Derived : public Base { public: // 继承构造 // 继承了父类的所有构造可以理解为编译器帮我们生成了上面的三个构造 using Base::Base; // 这样的话自己的成员就无法初始化了因为无法传参所以只能用缺省值 // 所以如果有自己的成员最好自己写构造 /*protected: int _i 0; string _s;*/ // 派生类有自己的成员时不适合用继承构造 // 综上继承构造适用于派生类没有成员或者是有成员但是不用显示给值只用缺省值即可 }; int main() { Derived d1(1); Derived d2(1.1); Derived d3(2, 2.2); return 0; }二. STL中的一些变化C11新增容器中最有用的是unordered_map和unordered_set。这 两个前面已经进行了非常详细的讲解。STL中容器的新接口也不少最重要的就是右值引用和移动语义相关的push/insert/emplace系列 接口和移动构造和移动赋值还有initializer_list版本的构造等这些前面都讲过了还有一些无关 痛痒的如cbegin/cend等需要时查查文档即可。范围for之前已经讲解过这里不再讲解如有遗忘可点击复习【C】unorderedset/map三. lambda3.1 lambda表达式语法lambda 表达式本质是一个匿名函数对象跟普通函数不同的是他可以定义在函数内部。 lambda 表达式语法使用层而言没有类型所以我们一般是用auto或者模板参数定义的对象去接收 lambda 对象。lambda表达式的格式 [capture-list] (parameters)- return type { function boby }[capture-list] : 捕捉列表该列表总是出现在 lambda 函数的开始位置编译器根据[]来判断接下来的代码是否为 lambda 函数捕捉列表能够捕捉上下文中的变量供 lambda 函数使用捕捉列表可以传值和传引用捕捉捕捉列表为空也不能省略。(parameters) 参数列表与普通函数的参数列表功能类似如果不需要参数传递则可以连 同()一起省略-return type 返回值类型用追踪返回类型形式声明函数的返回值类型没有返回值时此 部分可省略。一般返回值类型明确情况下也可省略由编译器对返回类型进行推导。{function boby} 函数体函数体内的实现跟普通函数完全类似在该函数体内除了可以 使用其参数外还可以使用所有捕获到的变量函数体为空也不能省略。// 尾置返回类型lambda和普通函数都有 // 尾置返回类型auto用于占位这样如果返回类比较长更容易看出看出函数名 std::mapstd::string, std::pairstd::string, std::string::iterator func(); auto func()-std::mapstd::string, std::pairstd::string, std::string::iterator; int main() { // 一个简单的lambda表达式 // 匿名函数对象 // 可以像函数一样使用底层是一个仿函数 //auto add1 [](int x, int y)-int {return x y; }; auto add1 [](int x, int y) {return x y; }; // 返回类型可以省略编译器会自动推导但是写出来更清晰 cout add1(1, 2) endl; //cout [](int x, int y)-int {return x y; }(1, 2) endl; // 不会这样用 // 1、捕捉为空也不能省略 // 2、参数为空可以省略 // 3、返回类型可以省略可以通过返回对象自动推导 // 4、函数体不能省略 auto func1 [] { cout hello bit endl; return 0; }; func1(); int a 0, b 1; auto swap1 [](int x, int y) { int tmp x; x y; y tmp; }; swap1(a, b); cout a : b endl; return 0; }3.2 捕捉列表lambda 表达式中默认只能用 lambda 函数体和参数中的变量如果想用外层作用域中的变量就需要进行捕捉第一种捕捉方式是在捕捉列表中显示的传值捕捉和传引用捕捉捕捉的多个变量用逗号分割。[x y z] 表示x和y值捕捉z引用捕捉。第二种捕捉方式是在捕捉列表中隐式捕捉我们在捕捉列表写一个表示隐式值捕捉在捕捉列表 写一个表示隐式引用捕捉这样我们 lambda 表达式中用了那些变量编译器就会自动捕捉那些 变量。第三种捕捉方式是在捕捉列表中混合使用隐式捕捉和显示捕捉。[, x]表示其他变量隐式值捕捉 x引用捕捉[, x, y]表示其他变量引用捕捉x和y值捕捉。当使用混合捕捉时第一个元素必须是 或并且混合捕捉时后面的捕捉变量必须是值捕捉同理混合捕捉时后面的捕捉变量必 须是引用捕捉。lambda 表达式如果在函数局部域中他可以捕捉 lambda 位置之前定义的变量不能捕捉静态局部变量和全局变量静态局部变量和全局变量也不需要捕捉 lambda 表达式中可以直接使用。这也意味着 lambda 表达式如果定义在全局位置捕捉列表必须为空。默认情况下 lambda 捕捉列表是被const修饰的也就是说传值捕捉的过来的对象不能修改 mutable加在参数列表的后面可以取消其常量性也就说使用该修饰符后传值捕捉的对象就可以修改了但是修改还是形参对象不会影响实参。使用该修饰符后参数列表不可省略(即使参数为空)。int x 0; // lambda写在全局捕捉列表必须为空因为全局变量不用捕捉就可以用没有可被捕捉的变量 auto func1 []() { x; }; // 在一个类的成员函数中写lambda class A { public: void func() { int x 0, y 1; // 隐式传值捕捉默认除了捕捉x和y也把this也捕捉过来了注只有用了才会捕捉这里的意思是this也能捕捉 // 可以捕捉_a1和_a2虽然不属于当前的局部域可以理解为把this捕捉了因为_a1和_a2是通过this访问的 auto f1 [] { _a1; // 可以修改 return x y _a1 _a2; }; cout f1() endl; // 隐式引用捕捉同上 auto f2 [] { x; _a1; // 可以修改 return x y _a1 _a2; }; cout f2() endl; // 捕捉this本质是可以访问成员变量 //auto f3 [x] // 如果显示传值捕捉只捕捉x则不能访问_a1和_a2因为没有this //auto f3 [x, _a1] // err这样也不行 auto f3 [x, this] { _a1; // 可以修改 return x _a1 _a2; }; cout f3() endl; } private: int _a1 0; int _a2 1; }; int main() { // 只能用当前lambda局部域捕捉的对象和全局对象 // 捕获列表的意义本质更方便的使用当前局部域的对象 int a 0, b 1, c 2, d 3; auto func1 [a, b] // 这里不是取地址而是引用捕捉 { // 值捕捉的变量不能修改引用捕捉的变量可以修改 //a; // 这里的a是外面a的拷贝默认是const不能修改 b; // 引用捕捉这里对b的修改就是对外面b的修改 int ret a b; x; return ret; }; // 传值捕捉加mutable就可以修改一般不会加 //auto func1 [a, b] () mutable // 用mutable必须加参数列表 // { // // 值捕捉的变量不能修改引用捕捉的变量可以修改 // a; // 这里的a是外面a的拷贝加mutable就可以修改注意传值捕捉里面改变不影响外面 // b; // 引用捕捉这里对b的修改就是对外面b的修改 // int ret a b; // x; // return ret; // }; cout func1() endl; // 隐式值捕捉 // 用了哪些变量就捕捉哪些变量所有都能用 auto func2 [] { int ret a b c d; return ret; }; cout func2() endl; // 隐式引用捕捉 // 用了哪些变量就捕捉哪些变量所有都能用 auto func3 [] { a; c; d; }; func3(); cout a b c d endl; // 混合捕捉1 // a和b值捕捉其他都是引用捕捉 //auto func4 [, a, b] err //auto func4 [a, , b] err auto func4 [, a, b] { // 值捕捉不能修改 //a; //b; c; d; return a b c d; }; func4(); cout a b c d endl; // 混合捕捉2 // a和b引用捕捉其他都是值捕捉 auto func5 [, a, b] { a; b; /*c; d;*/ return a b c d; }; func5(); cout a b c d endl; // 局部的静态和全局变量不能捕捉也不需要捕捉 // 可以直接使用因为他们的作用域/生命周期是全局的 static int m 0; auto func6 [] { int ret x m; return ret; }; // 传值捕捉本质是一种拷贝,并且被const修饰了 // mutable相当于去掉const属性可以修改了 // 但是修改了不会影响外面被捕捉的值因为是一种拷贝 auto func7 []()mutable { a; b; c; d; return a b c d; }; cout func7() endl; cout a b c d endl; // 虽然我们可以自己写仿函数但是用lambda更方便编译器可以帮助我们生成与范围for类似 return 0; }3.3 lambda的应用在学习 lambda 表达式之前我们的使用的可调用对象只有函数指针和仿函数对象函数指针的类型定义起来比较麻烦仿函数要定义一个类相对会比较麻烦。使用 lambda 去定义可调用对象既简单又方便。lambda 在很多其他地方用起来也很好用。比如线程中定义线程的执行函数逻辑智能指针中定制删除器等 lambda 的应用还是很广泛的。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 } }; // 类似这样的场景我们实现仿函数对象或者函数指针支持商品中 // 不同项的比较相对还是比较麻烦的那么这里lambda就很好用了 sort(v.begin(), v.end(), ComparePriceLess()); sort(v.begin(), v.end(), ComparePriceGreater()); // 使用lambdalambda是一个对象 // 传给auto /*auto priceLess [](const Goods gl, const Goods gr) { return gl._price gr._price; }; sort(v.begin(), v.end(), priceLess);*/ // 直接传对象更方便传给模板 sort(v.begin(), v.end(), [](const Goods gl, const Goods gr) { return gl._price gr._price; }); sort(v.begin(), v.end(), [](const Goods gl, const Goods gr) { return gl._price gr._price; }); sort(v.begin(), v.end(), [](const Goods gl, const Goods gr) { return gl._evaluate gr._evaluate; }); sort(v.begin(), v.end(), [](const Goods gl, const Goods gr) { return gl._evaluate gr._evaluate; }); return 0; }3.4 lambda的原理lambda 的原理和范围for很像编译后从汇编指令层的角度看压根就没有 lambda 和范围for这样的东西。范围for底层是迭代器而lambda底层是仿函数对象也就说我们写了一个 lambda 以后编译器会生成一个对应的仿函数的类。仿函数的类名是编译按一定规则生成的保证不同的 lambda 生成的类名不同lambda参数/返 回类型/函数体就是仿函数operator()的参数/返回类型/函数体lambda 的捕捉列表本质是生成的仿函数类的成员变量也就是说捕捉列表的变量都是 lambda 类构造函数的实参当然隐式捕捉编译器要看使用哪些就传那些对象。上面的原理我们可以透过汇编层了解一下下面第二段汇编层代码印证了上面的原理。// lambda的原理 class lambda8 { public: lambda8(int a_, int b_) :a(a_) , b(b_) { } int operator()(int x) { b; return a b x; } private: const int a; int b; }; auto func8 [a, b](int x) { b; return a b x; }; // 等价于 //lambda8 func8(a, b); //func8(1);通过汇编代码观察r1(10000, 2); 00D8297D push 2 00D8297F sub esp,8 00D82982 movsd xmm0,mmword ptr [__real40c3880000000000 (0D89B50h)] 00D8298A movsd mmword ptr [esp],xmm0 00D8298F lea ecx,[r1] 00D82992 call Rate::operator() (0D81212h) // 汇编层可以看到r2 lambda对象调用本质还是调用operator()类型是lambda_1,这个类型名 // 的规则是编译器自己定制的保证不同的lambda不冲突 r2(10000, 2); 00D82999 push 2 00D8299B sub esp,8 00D8299E movsd xmm0,mmword ptr [__real40c3880000000000 (0D89B50h)] 00D829A6 movsd mmword ptr [esp],xmm0 00D829AB lea ecx,[r2] 00D829AE call main::2::lambda_1::operator() (0D824C0h)四. 包装器4.1 functionstd::function是一个“万能容器”它可以存储任何“可调用对象”函数、Lambda、函数对象、成员函数等。template class T class function; // undefined template class Ret, class... Args class functionRet(Args...);std::function 是一个类模板也是一个包装器。 std::function 的实例对象可以包装存储其他的可以调用对象包括函数指针、仿函数、 lambda 、 bind 表达式等存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标则称它为空。调用空 std::function 的目标导致抛出 std::bad_function_call 异常。以上是 function 的原型他被定义头文件中。std::function - cppreference.com 是function的官方文件链接。函数指针、仿函数、 lambda 等可调用对象的类型各不相同 std::function 的优势就是统 一类型对他们都可以进行包装这样在很多地方就方便声明可调用对象的类型下面的第二个代 码样例展示了 std::function 作为map的参数实现字符串和可调用对象的映射表功能。int f(int a, int b) { return a b; } struct Functor { public: int operator() (int a, int b) { return a b; } }; class Plus { public: Plus(int n 10) :_n(n) { } static int plusi(int a, int b) { return a b; } double plusd(double a, double b) { return (a b) * _n; } private: int _n; }; int main() { // 包装各种可调用对象 // 类型擦除 // 包装函数指针仿函数lambda functionint(int, int) f1 f; functionint(int, int) f2 Functor(); functionint(int, int) f3 [](int a, int b) {return a b; }; cout f1(1, 1) endl; cout f2(1, 1) endl; cout f3(1, 1) endl; vectorfunctionint(int, int) v; v.push_back(f); v.push_back(Functor()); v.push_back([](int a, int b) {return a b; }); for (auto f : v) { cout f(1, 1) endl; } // 包装成员函数的指针 // 静态成员 //functionint(int, int) f4 Plus::plusi; functionint(int, int) f4 Plus::plusi; // 取地址最好还是加上 cout f4(1, 1) endl; // 调用方面 // 非静态成员注意还有一个this指针 functiondouble(Plus*, double, double) f5 Plus::plusd; Plus ps; cout f5(ps, 1.1, 1.1) endl; // 调用 // 其他写法 functiondouble(Plus, double, double) f6 Plus::plusd; cout f6(ps, 1.1, 1.1) endl; functiondouble(Plus, double, double) f7 Plus::plusd; cout f7(Plus(), 1.1, 1.1) endl; functiondouble(Plus, double, double) f8 Plus::plusd; cout f8(Plus(), 1.1, 1.1) endl; // 右值引用这里可以传匿名对象 // 为什么上面即可以传对象的指针也可以传对象 // 成员函数的指针 auto pf1 Plus::plusd; //cout pf1(ps, 1.1, 1.1); // 不能这样调用因为不能显示的传递this指针 cout (ps.*pf1)(1.1, 1.1) endl; // 对象的指针 Plus* ptr ps; cout (ptr-*pf1)(1.1, 1.1) endl; return 0; }#include iostream #include functional // 1. 普通函数 int add(int a, int b) { return a b; } // 2. 仿函数 (Functor) struct Subtract { int operator()(int a, int b) { return a - b; } }; // 3. 类成员函数 class Calculator { public: int multiply(int a, int b) { return a * b; } static int divide(int a, int b) { return a / b; } }; int main() { // 声明一个能接受两个 int 并返回 int 的 function std::functionint(int, int) op; // A. 包装普通函数 op add; std::cout Add: op(10, 5) std::endl; // 输出 15 // B. 包装 Lambda 表达式 op [](int a, int b) { return a % b; }; std::cout Mod: op(10, 3) std::endl; // 输出 1 // C. 包装仿函数 op Subtract(); std::cout Sub: op(10, 5) std::endl; // 输出 5 // D. 包装类静态成员函数 (和普通函数一样) op Calculator::divide; std::cout Div: op(10, 5) std::endl; // 输出 2 // E. 包装类非静态成员函数 (注意) // 非静态成员函数需要对象实例隐式的 this 指针 // std::function 的签名需要变更为int(Calculator*, int, int) 或者配合 bind 使用 return 0; }4.2 bindstd::bind是一个“适配器”它可以把一个函数预先固定某些参数或者改变参数的顺序生成一个新的可调用对象。simple(1) 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 是一个函数模板它也是一个可调用对象的包装器可以把他看做一个函数适配器对接收的fn可调用对象进行处理后返回一个可调用对象。bind 可以用来调整参数个数和参数顺序。 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为第二个参数以此类推。_1/_2/_3....这些占位符放到placeholders的一个命名空间中。#includefunctional using placeholders::_1; using placeholders::_2; using placeholders::_3; int Sub(int a, int b) { return (a - b) * 10; } int SubX(int a, int b, int c) { return (a - b - c) * 10; } class Plus { public: static int plusi(int a, int b) { return a b; } double plusd(double a, double b) { return a b; } }; int main() { // bind 本质返回的一个仿函数对象 // 调整参数顺序不常用 // _1代表第一个实参 // _2代表第二个实参 auto f1 bind(Sub, _1, _2); auto f2 bind(Sub, _2, _1); cout f1(10, 5) endl; // 50 cout f2(10, 5) endl; // -50 // 调整参数个数 // 编译器会根据占位符_1,_2来调整Sub的顺序或个数 auto f3 bind(SubX, 10, _2, _1); // 绑死第一个参数 cout f2(15, 5) endl; // 底层operator()调用SubX第一个参数10_1表示第一个实参_2表示第二个实参 auto f4 bind(SubX, _1, 10, _2); // 绑死第二个参数 cout f4(15, 5) endl; // 底层operator()调用SubX参数分别是15105 auto f5 bind(SubX, _1, _2, 10); // 绑死第三个参数 cout f5(15, 5) endl; // 底层operator()调用SubX参数分别是15510 // bind作用 functiondouble(Plus, double, double) f7 Plus::plusd; // 如果要进行多次调用每次都穿Plus()比较麻烦其他参数是变化的 // 绑定通常是这个参数在这一组参数中是固定的把它绑死 // 绑定返回的是一个可调用对象 cout f7(Plus(), 1.1, 1.1) endl; cout f7(Plus(), 1.1, 2.2) endl; cout f7(Plus(), 1.1, 3.3) endl; functiondouble(double, double) f8 bind(Plus::plusd, Plus(), _1, _2); cout f8(1.1, 1.1) endl; cout f8(1.1, 2.2) endl; cout f8(1.1, 3.3) endl endl; // 计算复利的lambda auto func1 [](double rate, double money, int year)-double { double ret money; for (int i 0; i year; i) { ret ret * rate; } return ret - money; }; functiondouble(double) func_r1_5_y3 bind(func1, 0.015, _1, 3); functiondouble(double) func_r1_5_y5 bind(func1, 0.015, _1, 5); functiondouble(double) func_r1_5_y20 bind(func1, 0.015, _1, 20); cout func_r1_5_y3(100000) endl; cout func_r1_5_y5(100000) endl; cout func_r1_5_y20(100000) endl; functiondouble(double) func_r10_y3 bind(func1, 0.1, _1, 3); functiondouble(double) func_r10_y5 bind(func1, 0.1, _1, 5); functiondouble(double) func_r10_y20 bind(func1, 0.1, _1, 20); cout func_r10_y3(100000) endl; cout func_r10_y5(100000) endl; cout func_r10_y20(100000) endl; return 0; }总结如有不足或改进之处欢迎大家在评论区积极讨论后续我也会持续更新C相关的知识。文章制作不易如果文章对你有帮助就点赞收藏关注支持一下作者吧让我们一起努力共同进步