C++第二十讲:C++11
- IT业界
- 2025-09-10 21:30:01

C++第二十讲:C++11 1.列表初始化1.1C++98时的{}初始化1.2C++11的新规{}初始化1.3initializer_list初始化 2.右值引用和移动语义2.1右值引用2.1.1左值和右值2.1.2左值引用和右值引用2.1.3引用延长声明周期2.1.4左值和右值的参数匹配 2.2右值引用和移动语义的使用2.2.1移动构造和移动赋值2.2.2特殊情况处理2.2.3不同情况编译器优化分析 2.3类型分类 -- 了解2.4引用折叠2.5完美转发 3.可变参数模板3.1基本语法及原理3.2包扩展3.3emplace系列接口 4.新的类功能4.1默认的移动构造和移动赋值4.2声明时给缺省值 && final与override4.3default和delete4.4STL中的一些变化 5.lambda5.1lambda表达式的语法5.2捕捉列表5.3lambda的应用 -- 自定义sort5.4lambda的原理 6.包装器6.1function6.2bind 1.列表初始化 1.1C++98时的{}初始化
C++98时,仅支持数组和结构体对象的{}初始化,也叫做列表初始化:
//C++98时的传统{}初始化 struct Point { int _x; int _y; }; int main() { //1.数组的列表初始化 int a[] = { 1, 2, 3, 4 }; int arr[10] = { 0 }; //2.结构体的列表初始化 Point point = { 1,2 }; return 0; } 1.2C++11的新规{}初始化1.C++11希望实现一切类型的对象都可以使用{}初始化,也就是列表初始化,其中,自定义类型的列表初始化会被编译器从构造临时对象 + 拷贝构造优化为直接构造 2.{}初始化的过程中,可以省略掉=
//C++11的新规{}初始化 class Date { public: Date(int year = 1, int month = 1, int day = 1) :_year(year) , _month(month) , _day(day) { cout << "Date(int year, int month, int day)" << endl; } Date(const Date& d) :_year(d._year) , _month(d._month) , _day(d._day) { cout << "Date(const Date& d)" << endl; } private: int _year; int _month; int _day; }; int main() { //1.内置类型支持列表初始化 int x = { 3 }; //2.自定义类型的列表初始化 const Date& d1 = {2024, 1, 1};//d1引用的是临时对象 Date d2 = {2024, 1}; Date d3 = {2024}; Date d4 = 2024;//Data中包含全缺省的构造函数,支持单参数时类型转换,可以省略{} //3.仅对于{}初始化,可以省略{} int x2{3}; Date d5{2024, 2, 2}; const Date& d5{2024, 3, 2}; //4.{}初始化的优化实现 vector<Date> v; v.push_back(Date(2021, 1, 1)); v.push_back({2021, 2, 1}); return 0; } 1.3initializer_list初始化1.initializer_list支持多个值去构造初始化 2.initializer_list底层其实是为插入的数据开辟了一块数组,然后包含两个指向数组begin和end的指针,所以initializer_list对象的大小为8个字节(x86下)
//initializer_list初始化 int main() { //1.数组大小为8个字节 std::initializer_list<int> mylist; mylist = { 10, 20, 30 }; cout << sizeof(mylist) << endl;//x86下,8个字节 //2.数组的地址和i的地址很接近,说明数组存在栈上 int i = 0; cout << mylist.begin() << endl; cout << mylist.end() << endl; cout << &i << endl; //3.两个写法的不同差别: //3.1.直接构造 //3.2.构造临时对象 + 临时对象拷贝构造v2 --> 优化为直接构造 vector<int> v1({ 1, 2, 3, 4, 5 }); vector<int> v2 = { 2, 3, 4 }; //4.赋值支持 v1 = { 10,20,30,40,50 }; return 0; } 2.右值引用和移动语义 2.1右值引用 2.1.1左值和右值左值和右值的区别可以看作是:是否可以进行取地址操作
int main() { //左值:可以取地址 //以下的p、b、c、*p、s、s[0]就是常⻅的左值 int* p = new int(0); int b = 1; const int c = b; *p = 10; string s("111111"); s[0] = 'x'; //右值:不可以取地址 double x = 1.1, y = 2.2; // 以下⼏个10、x + y、fmin(x, y)、string("11111")都是常⻅的右值 10; x + y; fmin(x, y); string("11111"); return 0; } 2.1.2左值引用和右值引用1.左值引用:int b = 1; int& a = b 右值引用:int&& a = 1; 2.左值引用不能引用右值,但加上const&可以引用右值,右值引用在使用move函数的情况下可以引用左值【move(左值)】 3.左值引用和右值引用本质都是给左值/右值取别名,底层都是通过指针实现的 4.move是库里面的一个函数模板,本质是强制类型转化,涉及了一些模板折叠的问题,这些后面会讲 5.需要注意的是,虽然右值被右值引用绑定后,右值引用变量的属性是左值
int main() { //1.左值引用和右值引用语法 int b = 2; int& a = b; int&& c = 1; //2.const左值引用可以引用右值 //move(左值)可以被右值引用 const int& d = 1; int&& e = move(b);//此时的e是左值属性 e = 10; return 0; } 2.1.3引用延长声明周期右值引用可以用来延长声明周期,虽然const左值引用也可以用来延长声明周期,但是const表示无法被修改:
int main() { string s1 = "Test"; const string& s2 = s1 + s1;//也可以引用右值,但是s2无法被修改 string&& s3 = s1 + s1; s1 += "Test"; cout << s3 << endl;//TestTest return 0; } 2.1.4左值和右值的参数匹配对于函数重载,不同的参数匹配到的函数是不同的,那么我们就可以利用这一规则进行代码的编写:
void f(int& x) { std::cout << "左值引⽤重载 f(" << x << ")\n"; } void f(const int& x) { std::cout << "到 const 的左值引⽤重载 f(" << x << ")\n"; } void f(int&& x) { std::cout << "右值引⽤重载 f(" << x << ")\n"; } int main() { int i = 1; const int ci = 2; f(i); // 调⽤ f(int&) f(ci); // 调⽤ f(const int&) f(3); // 调⽤ f(int&&),如果没有 f(int&&) 重载则会调⽤ f(const int&) f(std::move(i)); // 调⽤ f(int&&) return 0; } 2.2右值引用和移动语义的使用 2.2.1移动构造和移动赋值 2.2.2特殊情况处理 2.2.3不同情况编译器优化分析移动构造和拷贝构造的区别就在于是否实现了移动构造/移动赋值,而下面的优化情况都是在VS2019或者VS2022版本的优化,所以对于老式的版本来说,移动构造和移动赋值的作用就凸显出来了 1.两个拷贝构造 – 通过删除临时对象的方式实现一个拷贝构造 2.两个移动构造 – 也是删除临时对象,直接进行移动构造 3.拷贝构造 + 拷贝赋值 – 先创建临时对象,str指向临时对象的引用,底层是指针的使用 4.移动构造 + 移动赋值 5.VS2019release版本和VS2022版本的优化有所不同,会优化地更加恐怖:
2.3类型分类 – 了解C++11以后,进一步对右值进行了划分,将右值划分为纯右值和将亡值:
C++11标准中,vector等一系列容器的构造器实现都引用了一个右值引用参数实现的构造,它的作用是支持移动语义和完美转发,下面会讲到完美转发
2.4引用折叠C++中并不支持int& && r = i的实现,但是我们通过typedef可以实现类似的操作,这里面就涉及到一个引用折叠的知识: 1.引用折叠的目的在于能够实现模板参数的准确传递,针对于不同的类型有针对性的措施实施 2.右值引用的右值引用折叠成为右值引用,其它情况均折叠为左值应用,也就是当存在左值引用,就会被折叠为左值引用 3.对于函数模板来说,函数参数为T&,那么只能接收左值,如果函数参数为T&&,那么就是万能引用,可以接收左值和右值
引用折叠的使用:
//引用折叠的使用 int main() { typedef int& lref; typedef int&& rref; int n = 0; lref& r1 = n; // r1 的类型是 int& lref&& r2 = n; // r2 的类型是 int& rref& r3 = n; // r3 的类型是 int& rref&& r4 = 1; // r4 的类型是 int&& return 0; }引用折叠的使用情况举例:
template<class T> void f1(T& x) {} template<class T> void f2(T&& x) {} int main() { int n = 0; f1<int>(n); f1<int>(0);//左值引用不能引用右值,报错 f1<int&>(n);//int&是一个左值引用,有左值引用就会折叠为左值引用 f1<int&>(0);//左值引用无法引用右值 f1<int&&>(n);//f1的参数是左值引用,所以折叠完还是左值引用 f1<int&&>(0);//左值引用无法引用右值 f1<const int&>(n);//const左值引用可以引用左值和右值 f1<const int&>(0); f1<const int&&>(n);//const左值引用可以引用左值和右值 f1<const int&&>(0); f2<int>(n);//右值引用无法引用左值 f2<int>(0); f2<int&>(n); f2<int&>(0);//左值引用无法引用右值 f2<int&&>(n);//两个右值引用折叠为右值引用,右值引用无法引用左值 f2<int&&>(0); return 0; }引用折叠的使用场景:
//这里实现的是一个万能引用 template<class T> void Function(T&& t) { int a = 0; T x = a; //x++; cout << &a << endl; cout << &x << endl << endl; } //总结: //当实参是右值,编译器推导的T并不带&,而是一个类型,没有引用折叠 //当实参是左值,编译器推导的T带&,会进行引用折叠 int main() { //10是一个右值,编译器推导出T=int,模板实例化为void Function(int&& t) Function(10); //a是一个左值,编译器推导出T=int&,引用折叠,模板实例化为void Function(int& t) int a; Function(a); //右值,推导出T=int,实例化为void Function(int&& t) Function(std::move(a)); //左值,T=const int&,实例化为void Function(const int& t) //此时Function中的x不能进行++操作 const int b = 8; Function(b); //T=const int //不能修改x Function(std::move(b)); return 0; } 2.5完美转发当函数接收的参数是int&& x时,此时的x是左值,Func(x)匹配到的函数并不是所希望的右值函数,而会匹配到左值函数,此时可以使用完美转发来解决这个问题:
不使用完美转发时会遇到的问题:
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; } template<class T> void Function(T&& t) { Fun(t);//此时会进入Fun(int& x); 或者Fun(const int &);函数 } int main() { Function(10);//进入Fun(int& x) const int a = 1; Function(std::move(a));//进入Fun(const int &) return 0; }使用完美转发的问题解决方法:
#include<utility>//forward 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; } template<class T> void Function(T&& t) { //Fun(t); Fun(forward<T>(t)); } int main() { Function(10);//右值引用 const int a = 1; Function(std::move(a));//const 右值引用 return 0; } 3.可变参数模板 3.1基本语法及原理C++11开始支持可变数量参数的函数模板和类模板,可变数量的参数称为参数包,存在两种参数包:1.模板参数包,表示零个或多个模板参数。2.函数参数包:表示零个或多个函数参数:
template<class...Args> void Func1(Args...args) {} template<class...Args> void Func2(Args&...args) {} template<class...Args> void Func3(Args&&...args) {}上面显示的就是函数参数包和模板参数包的定义,函数参数包可以用左值引用或右值引用(其实是万能引用)表示,此时会发生引用折叠,下面我们看一下可变参数模板的使用:
1.使用sizeof来计算函数参数包接收的实参的个数
//1.可以使用sizeof来计算出函数参数包接收的实参个数 template<class...Args> void Print(Args&&...args) { cout << sizeof...(args) << endl; } int main() { Print(1); Print(10, 'x'); Print(10, 'x', "xxxx"); return 0; }2.可变参数模板的本质其实是编译器实例化出对应类型的多个函数
3.可变参数模板的好处在于省略了自己实现多个函数模板的操作
3.2包扩展对于一个参数包,我们除了能够计算出包中元素的个数,还应该能够将一个包分解为它构成的元素,而包扩展其实就是允许参数包在合适的位置展开为多个元素,用来实现模板函数的灵活处理
1.一个简单的包扩展 – 提取包中的所有元素
void ShowList() { cout << "ShowList()" << endl; } template<class T, class...Args> void ShowList(T t, Args&&...args) { cout << t << " " << endl; ShowList(args...); } template<class...Args> void Print(Args&&...args) { cout << "一共有" << sizeof...(args) << "个实参" << endl; ShowList(args...); } int main() { Print(10, string("xxxxxx"), 1.1); return 0; }2.一个复杂的包扩展 – 也是拿到所有的实参
template <class T> const T& GetArg(const T& x) { cout << x << " "; return x; } template <class ...Args> void Arguments(Args... args) {} template <class ...Args> void Print(Args... args) { Arguments(GetArg(args)...); } int main() { Print(10, string("xxxxxx"), 1.1); return 0; } 3.3emplace系列接口C++11之后的STL容器新增了emplace系列的接口,emplace接口均为模板可变参数,功能上支持push和insert系列,而且要比push和insert接口效率要高,所以推荐使用emplace系列接口
1.emplace接口和普通函数接口的不同:
2.emplace接口更高效的原因:
4.新的类功能 4.1默认的移动构造和移动赋值1.原来C++类中,有6个默认成员函数:构造函数、析构函数、拷贝构造函数、拷贝赋值重载、取地址重载、const取地址重载,C++11新增了两个新的默认成员函数:移动构造函数和移动赋值运算符重载 2.如果没有自己实现的析构函数、拷贝构造、拷贝赋值重载,而且没有自己实现移动构造,系统会自动生成一个移动构造,对于内置类型,进行逐字节拷贝,自定义类型,有移动构造,调用移动构造,没有移动构造,调用拷贝构造 3.移动赋值生成的条件和上面一样,唯一不同的是对于内置类型,没有实现移动赋值,调用拷贝赋值 4.如果自己实现了移动构造和移动赋值,那么编译器就不会自动生成拷贝构造和拷贝赋值
4.2声明时给缺省值 && final与override这两个知识点前面已经讲过: 声明时给缺省值:类和对象 final与override:继承和多态
4.3default和delete当我们实现了拷贝构造,那么编译器就不会自动生成移动构造了,此时我们可以使用default来指定移动构造生成:
Person(const Person& p) :_name(p._name) , _age(p._age) {} Person(Person&& p) = default;delete的使用可以自己查找
4.4STL中的一些变化5.lambda 5.1lambda表达式的语法
lambda表达式格式为:[capture-list] (parameters) -> return type {function body}: 1.capture-list:捕捉列表,下面会详细解释 2.parameters:参数列表,可以实现全缺省的参数,也就是可以对形参进行初始化 3.return type:返回类型 4.function body:函数体,和平常自己实现的函数体相同
1.lambda表达式的使用:
int main() { //lambda表达式对于使用层而言没有类型,底层是编译器通过传入的参数和返回值创建出的 //一个仿函数,该函数的类型取决于编译器,所以说我们一般使用auto接收lambda对象 auto add1 = [](int x, int y)->int {return x + y; }; //auto add1 = [](int x = 1, int y = 2)->int {return x + y; }; //全缺省 int a = add1(1, 2); cout << a << endl; return 0; }2.lambda表达式的使用注意:
int main() { //1.捕捉列表为空也不能省略 //2.参数可以省略 //3.返回值可以省略 -- 不建议省略,除非void返回 //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; } 5.2捕捉列表1.lambda表达式默认只能使用参数列表和函数体中创建的变量,以及全局/局部静态变量,对于作用域内的变量就需要通过捕捉来使用(全局变量和static静态变量可以使用,但是不能捕捉) 2.显示捕捉分为两种:传值捕捉:[x, y], 传引用捕捉:[&x, &y],可以混合使用:[x, &y] 3.隐示捕捉分为两种:隐式值捕捉:[=], 隐式引用捕捉:[&],当lambda表达式中使用到了那些参数,就可以自动捕捉哪些参数 4.可以混合使用隐式捕捉和显示捕捉,[=, &x, &y]表示其它变量隐式捕捉,x和y显示捕捉。 [&, x, y]表示其它变量隐式引用捕捉,x和y显示捕捉 5.其它情况的捕捉是非法的,比如:[=, x, &y]、[&, x, &y]、[=, &] 6.传值捕捉和传引用捕捉的区别在于:传值捕捉不能够修改捕捉的值,传引用捕捉可以修改捕捉的值 7.传值捕捉的本质是一种拷贝,并且加上const修饰,mutable相当于去掉const属性,可以修改了,但是修改不影响外面捕捉的值,因为只是一种拷贝
int x = 0; int main() { int a = 0, b = 1, c = 2, d = 3; auto func1 = [a, &b] { //a++ //报错:值捕捉不能修改 b++;//引用捕捉可以修改 int ret = a + b; return ret; }; cout << func1() << endl; //隐式值捕捉 auto func2 = [=] { int ret = a + b + c; return ret; }; cout << func2() << endl; //隐式引⽤捕捉 auto func3 = [&] { a++; c++; d++; }; func3(); 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++; return a + b + c + d; }; cout << func7() << endl; cout << a << " " << b << " " << c << " " << d << endl; return 0; } 5.3lambda的应用 – 自定义sort1.当我们需要自定义sort时,之前使用仿函数来进行自定义操作:
#include <algorithm>//sort 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() { vector<Goods> v = { { "苹果", 2.1, 5 }, { "⾹蕉", 3, 4 }, { "橙⼦", 2.2, 3}, { "菠萝", 1.5, 4 } }; //自定义仿函数进行自定义类型的排序 sort(v.begin(), v.end(), ComparePriceLess()); sort(v.begin(), v.end(), ComparePriceGreater()); return 0; }2.使用lambda的优化:
#include <algorithm>//sort 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() { vector<Goods> v = { { "苹果", 2.1, 5 }, { "⾹蕉", 3, 4 }, { "橙⼦", 2.2, 3}, { "菠萝", 1.5, 4 } }; sort(v.begin(), v.end(), ComparePriceLess()); sort(v.begin(), v.end(), ComparePriceGreater()); //使用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; }); 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; }); return 0; } 5.4lambda的原理1.lambda的底层是仿函数对象,也就是说,当我们写了一个lambda以后,编译器会生成一个对应的仿函数的类 2.仿函数的类是按照一定的规则生成的,保证不同的lambda生成的类名不同(lambda+uid),lambda参数/返回类型/函数体就是仿函数operator()的参数/返回类型/函数体 3.lambda捕捉列表的本质是生成的仿函数的成员变量,也就是捕捉列表的变量都是lambda类构造函数的实参。对于隐式捕捉,编译器要看使用了哪些变量,就传那些变量
我们从汇编的角度来理解:
6.包装器 6.1functionstd:function是一个类模板,也是一个包装器,可以对函数指针、仿函数、lambda表达式、bind表达式等进行包装,它的优势就是将不同类型的函数进行类型统一,这样就方便对调用对象的类型进行声明:
1.function包装的使用:
#include <functional>//function int f(int a, int b) { return a + b; } struct Functor { int operator()(int a, int b) { return a + b; } }; int main() { function<int(int, int)> f1 = f;//包装全局函数 function<int(int, int)> f2 = Functor();//包装仿函数 function<int(int, int)> f3 = [](int a, int b) {return a + b; };//包装lambda表达式 cout << f1(1, 2) << endl; cout << f2(1, 2) << endl; cout << f3(1, 2) << endl; return 0; }function对于成员函数的包装:
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() { //包装静态成员函数 //1.静态成员函数的包装:指定类域 + &符号 function<int(int, int)> f1 = &Plus::plusi; cout << f1(1, 2) << endl; //包装普通成员函数 //2.成员函数的包装:成员函数隐藏着一个this指针变量,所以需要再多传入一个参数 function<double(Plus*, double, double)> f2 = &Plus::plusd;//写法1 Plus ps;//对应的用法 cout << f2(&ps, 1.1, 1.1) << endl; function<double(Plus, double, double)> f3 = &Plus::plusd;//写法2 cout << f3(Plus(), 1.1, 1.1) << endl; cout << f3(ps, 1.1, 1.1) << endl; function<double(Plus&&, double, double)> f4 = &Plus::plusd;//写法3 cout << f4(move(ps), 1.1, 1.1) << endl; cout << f4(Plus(), 1.1, 1.1) << endl; return 0; }之前我们写过一道题,我们回顾一下: 这道题的思路为:拿到数字就入栈,拿到运算符就出栈,然后通过分析拿到的运算符来进行相应的计算操作
6.2bindbind也在functional头文件中,调用bind的一般格式为:auto newCallable = bind(callable, arg_list),它的作用为绑定一个函数的参数,自定义实参的对应对象,其中_1永远指向第一个实参,_2永远指向第二个实参……,_1/_2等被放在placeholders的一个命名空间中:
1.绑定用法:
#include <functional> using placeholders::_1; using placeholders::_2; using placeholders::_3; int Sub(int a, int b) { return (a - b) * 10; } int main() { //绑定一个函数,_1为第一个实参,_2为第二个实参 auto sub1 = bind(Sub, _1, _2); cout << sub1(10, 5) << endl;//10-5 auto sub2 = bind(Sub, _2, _1); cout << sub2(10, 5) << endl;//5-10 return 0; }绑定常见使用:
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() { //1.调整参数个数 auto sub1 = bind(Sub, 100, _1); auto sub2 = bind(Sub, _1, 100); cout << sub1(20) << endl;//800 cout << sub2(20) << endl;//-800 //2.绑死一些参数 auto sub5 = bind(SubX, 100, _1, _2); cout << sub5(5, 1) << endl; auto sub6 = bind(SubX, _1, 100, _2); cout << sub6(5, 1) << endl; auto sub7 = bind(SubX, _1, _2, 100); cout << sub7(5, 1) << endl; //3.成员函数对象进行绑死,就不需要每次都传递了 function<double(Plus&&, double, double)> f6 = &Plus::plusd; Plus pd; cout << f6(move(pd), 1.1, 1.1) << endl; cout << f6(Plus(), 1.1, 1.1) << endl; //绑死后 function<double(double, double)> f7 = bind(&Plus::plusd, Plus(), _1, _2); cout << f7(1.1, 1.1) << endl; return 0; }例子说明:
using placeholders::_1; using placeholders::_2; using placeholders::_3; int main() { //计算复利的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; }; //绑死⼀些参数,实现出⽀持不同年华利率,不同⾦额和不同年份计算出复利的结算利息 function<double(double)> func3_1_5 = bind(func1, 0.015, _1, 3); function<double(double)> func5_1_5 = bind(func1, 0.015, _1, 5); function<double(double)> func10_2_5 = bind(func1, 0.025, _1, 10); function<double(double)> func20_3_5 = bind(func1, 0.035, _1, 30); cout << func3_1_5(1000000) << endl; cout << func5_1_5(1000000) << endl; cout << func10_2_5(1000000) << endl; cout << func20_3_5(1000000) << endl; return 0; }C++第二十讲:C++11由讯客互联IT业界栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++第二十讲:C++11”