首页 > 编程语言 >c++11(下篇)

c++11(下篇)

时间:2024-11-03 15:16:25浏览次数:3  
标签:11 下篇 函数 int c++ return 参数 捕捉 lambda

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

承接上文c++11(上篇),上文主要讲解了初始化列表,右值引用和移动语义等相关知识,下面将会由此深入并扩展c++11中的重要概念
此外在了解一个知识点的时候,作者会先介绍其面对的问题,再讲解概念是如何解决这个问题的


一、可变参数模板

通俗的讲可变参数模板其实就是模板的模板,当我们使用单一的模板函数的时候,当我们面对参数数量不确定的时候,例如:

void Print()
{};

int main()
{
 double x = 2.2;
 Print(); // 包⾥有0个参数 
 Print(1); // 包⾥有1个参数 
 Print(1, string("xxxxx")); // 包⾥有2个参数 
 Print(1.1, string("xxxxx"), x); // 包⾥有3个参数 
 return 0;
}

难道我们要写四个函数模板去实现函数的进行吗?
此时可变参数模板应运而生

4.1 基本语法及原理

• C++11⽀持可变参数模板,也就是说⽀持可变数量参数的函数模板和类模板,可变数⽬的参数被称
为参数包,存在两种参数包:模板参数包,表⽰零或多个模板参数;函数参数包:表⽰零或多个函
数参数。
• template <class …Args> void Func(Args… args) {}
• template <class …Args> void Func(Args&… args) {}
• template <class …Args> void Func(Args&&… args) {}
• 我们⽤省略号来指出⼀个模板参数或函数参数的表⽰⼀个包,在模板参数列表中,class…或
typename…指出接下来的参数表⽰零或多个类型列表;在函数参数列表中,类型名后⾯跟…指出
接下来表⽰零或多个形参对象列表;函数参数包可以⽤左值引⽤或右值引⽤表⽰,跟前⾯普通模板
⼀样,每个参数实例化时遵循引⽤折叠规则。
• 可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。
• 这⾥我们可以使⽤sizeof…运算符去计算参数包中参数的个数。

template <class ...Args>
void Print(Args&&... args)
{
 cout << sizeof...(args) << endl;
}
int main()
{
 double x = 2.2;
 Print(); // 包⾥有0个参数 
 Print(1); // 包⾥有1个参数 
 Print(1, string("xxxxx")); // 包⾥有2个参数 
 Print(1.1, string("xxxxx"), x); // 包⾥有3个参数 
 return 0;
}

// 原理1:编译本质这⾥会结合引⽤折叠规则实例化出以下四个函数 
void Print();
void Print(int&& arg1);
void Print(int&& arg1, string&& arg2);
void Print(double&& arg1, string&& arg2, double& arg3);
// 原理2:更本质去看没有可变参数模板,我们实现出这样的多个函数模板才能⽀持 
// 这⾥的功能,有了可变参数模板,我们进⼀步被解放,他是类型泛化基础 
// 上叠加数量变化,让我们泛型编程更灵活。 
void Print();
template <class T1>
void Print(T1&& arg1);
template <class T1, class T2>
void Print(T1&& arg1, T2&& arg2);
template <class T1, class T2, class T3>
void Print(T1&& arg1, T2&& arg2, T3&& arg3);

• 可变参数模板的原理跟模板类似,本质还是去实例化对应类型和个数的多个函数。
• 这⾥我们可以使⽤sizeof…运算符去计算参数包中参数的个数。

4.2 包扩展

当我们看完4.1的内容时还并没有感觉到其语法上的难度,但是我们继续往下面想:函数内部如何使用这些可变参数模板实例化出的参数呢?

• 对于⼀个参数包,我们除了能计算他的参数个数,我们能做的唯⼀的事情就是扩展它,当扩展⼀个
包时,我们还要提供⽤于每个扩展元素的模式,扩展⼀个包就是将它分解为构成的元素,对每个元
素应⽤模式,获得扩展后的列表。我们通过在模式的右边放⼀个省略号(…)来触发扩展操作。底层
的实现细节如图1所⽰。
• C++还⽀持更复杂的包扩展,直接将参数包依次展开依次作为实参给⼀个函数去处理

在这里插入图片描述
相当于再设定一个函数来递归获取每一个参数,将参数包扩展开来。

// 可变模板参数 
// 参数类型可变 
// 参数个数可变 
// 打印参数包内容 
//template <class ...Args>
//void Print(Args... args)
//{
// // 可变参数模板编译时解析 
// // 下⾯是运⾏获取和解析,所以不⽀持这样⽤ 
// cout << sizeof...(args) << endl;
// for (size_t i = 0; i < sizeof...(args); i++)
// {
// cout << args[i] << " ";
// }
// cout << endl;
//}
void ShowList()
{
 // 编译器时递归的终⽌条件,参数包是0个时,直接匹配这个函数 
 cout << endl;
}
template <class T, class ...Args>
void ShowList(T x, Args... args)
{
 cout << x << " ";
 // args是N个参数的参数包 
 // 调⽤ShowList,参数包的第⼀个传给x,剩下N-1传给第⼆个参数包 
 ShowList(args...);
}
// 编译时递归推导解析参数 
template <class ...Args>
void Print(Args... args)
{
 ShowList(args...);
}
int main()
{
 Print();
 Print(1);
 Print(1, string("xxxxx"));
 Print(1, string("xxxxx"), 2.2);
 return 0;
}

4.3 empalce系列接⼝

emplace系列的接口上的参数就使用到了可变参数模板概念。

• template <class… Args> void emplace_back (Args&&… args);
• template <class… Args> iterator emplace (const_iterator position, Args&&… args)

先来看一下与同功能的函数push_back()的对比

#include<list>
// emplace_back总体⽽⾔是更⾼效,推荐以后使⽤emplace系列替代insert和push系列 
int main()
{
 list<bit::string> lt;
 // 传左值,跟push_back⼀样,⾛拷⻉构造 
 bit::string s1("111111111111");
 lt.emplace_back(s1);
 cout << "*********************************" << endl;
 // 右值,跟push_back⼀样,⾛移动构造 
 lt.emplace_back(move(s1));
 cout << "*********************************" << endl;
// 直接把构造string参数包往下传,直接⽤string参数包构造string 
 // 这⾥达到的效果是push_back做不到的 ,因为push_back会发生一层隐式类型转换
 lt.emplace_back("111111111111");
 cout << "*********************************" << endl;
 list<pair<bit::string, int>> lt1;
 // 跟push_back⼀样 
 // 构造pair + 拷⻉/移动构造pair到list的节点中data上 
 pair<bit::string, int> kv("苹果", 1);
 lt1.emplace_back(kv);
 cout << "*********************************" << endl;
 // 跟push_back⼀样 
 lt1.emplace_back(move(kv));
 cout << "*********************************" << endl;
 
 // 直接把构造pair参数包往下传,直接⽤pair参数包构造pair 
 // 这⾥达到的效果是push_back做不到的 
 lt1.emplace_back("苹果", 1);
 cout << "*********************************" << endl;
 return 0;
}

总结:emplace系列基本包含insert和push_back的功能,并且在某些场景下更为优秀。

二、lambda

当我们在使用sort这种比较函数的时候,有时候会需要自己设计类里面的变量该怎么去比较,这时候我们可能需要引入仿函数的概念,但是还是会有一定的麻烦,这时候lambda就是来解决类似的问题的。

2.1.仿函数

仿函数(Functor)是一个重载了operator()的类或结构体实例,这使得它可以像函数一样被调用。仿函数的概念是C++函数对象(Function Object)的一种实现方式,它提供了比传统函数指针更丰富的功能,比如可以携带状态(通过成员变量)。

struct Add {  
    int operator()(int a, int b) const {  
        return a + b;  
    }  
};
//在这个例子中,Add是一个仿函数类型,它的实例可以像函数一样被调用:
Add add;  //定义类的对象
int result = add(3, 4); // 调用仿函数,result将是7

其实lambda的底层原理还是 仿函数,只不过当我们写了lambda之后会由编译器进行处理
C++11引入的lambda表达式进一步简化了仿函数的创建和使用,使得C++的函数式编程风格更加易于实现和理解。

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 } };
 // 类似这样的场景,我们实现仿函数对象或者函数指针⽀持商品中 
 // 不同项的⽐较,相对还是⽐较⿇烦的,那么这⾥lambda就很好⽤了 

//仿函数
 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;
}

此外再了解lambda语法的前面我们先了解一下辅助知识:
函数对象:

函数对象(Function Object)在C++中是一个非常重要的概念,它指的是任何可以像函数一样被调用的对象。这个术语涵盖了多种实体,包括但不限于普通函数、函数指针、成员函数指针、以及重载了operator()的类或结构体实例(通常称为仿函数或functor)

匿名函数对象通常通过lambda表达式(lambda function)来创建。Lambda表达式提供了一种简洁的方式来定义和使用局部函数对象,而无需显式地定义一个类

2.2.lambda表达式语法

• lambda 表达式本质是⼀个匿名函数对象,跟普通函数不同的是他可以定义在函数内部。
lambda 表达式语法使⽤层⽽⾔没有类型,所以我们⼀般是⽤auto或者模板参数定义的对象去接
收 lambda 对象。

• lambda表达式的格式: [capture-list] (parameters)-> return type { function boby }

以下是语法格式的四个组成部分

• [capture-list] :捕捉列表,该列表总是出现在 lambda 函数的开始位置,编译器根据[]来
判断接下来的代码是否为 lambda 函数,捕捉列表能够捕捉上下⽂中的变量供 lambda 函数使
⽤,捕捉列表可以传值和传引⽤捕捉,具体细节7.2中我们再细讲。捕捉列表为空也不能省略。
• (parameters) :参数列表,与普通函数的参数列表功能类似,如果不需要参数传递,则可以连
同()⼀起省略
• ->return type :返回值类型,⽤追踪返回类型形式声明函数的返回值类型,没有返回值时此
部分可省略。⼀般返回值类型明确情况下,也可省略,由编译器对返回类型进⾏推导。
• {function boby} :函数体,函数体内的实现跟普通函数完全类似,在该函数体内,除了可以
使⽤其参数外,还可以使⽤所有捕获到的变量,函数体为空也不能省略。

int main()
{
 // ⼀个简单的lambda表达式 
 auto add1 = [](int x, int y)->int {return x + y; };
 cout << add1(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;
}

以下是对 auto add1 = [](int x, int y)->int {return x + y; };的解释

auto:这是C++11中引入的自动类型推导关键字。在这里,它用于告诉编译器自动推导add1的类型。由于add1是一个lambda表达式,编译器会将其推导为一个独特的、匿名的函数对象类型,所以add1并不是函数名而是一个对象!!!
[]:这是lambda表达式的捕获列表。捕获列表用于指定lambda表达式体内可以访问的外部变量。在这个例子中,捕获列表为空,意味着lambda表达式体内不能访问任何外部变量(除非它们是通过值捕获或引用捕获显式地添加的)。
(int x, int y):这是lambda表达式的参数列表。它指定了lambda表达式接受的参数类型和数量。在这个例子中,lambda表达式接受两个整数参数x和y。
->int:这是lambda表达式的返回类型。它指定了lambda表达式返回值的类型。在这个例子中,lambda表达式返回一个整数。注意,如果lambda表达式的体非常简单,并且其返回类型可以从返回语句中直接推导出来,那么可以省略返回类型(但前提是编译器能够正确推导)。然而,在更复杂的lambda表达式中,或者当您希望明确指定返回类型以避免潜在的二义性时,提供返回类型是一个好习惯。
{return x + y; }:这是lambda表达式的体。它包含了lambda表达式要执行的代码。在这个例子中,lambda表达式的体只是简单地返回了两个参数的和。

2.3. 捕捉列表

• 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;
// 捕捉列表必须为空,因为全局变量不⽤捕捉就可以⽤,没有可被捕捉的变量 
auto func1 = []()
{
 x++;
};
int main()
{
 // 只能⽤当前lambda局部域和捕捉的对象和全局对象 
 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;
 // 混合捕捉1 
 auto func4 = [&, a, b]
 {
 //a++;
 //b++;
 c++;
 d++;
 return a + b + c + d;
 };
 func4();
 cout << a << " " << b << " " << c << " " << d << endl;
 // 混合捕捉1 
 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;
 return 0;
}

2.3lambda原理

• lambda 的原理和范围for很像,编译后从汇编指令层的⻆度看,压根就没有 lambda 和范围for
这样的东西。范围for底层是迭代器,⽽lambda底层是仿函数对象,也就说我们写了⼀个lambda 以后,编译器会⽣成⼀个对应的仿函数的类。
• 仿函数的类名是编译按⼀定规则⽣成的,保证不同的 lambda ⽣成的类名不同,lambda参数/返回类型/函数体就是仿函数operator()的参数/返回类型/函数体, 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;
 // lambda
 auto r2 = [rate](double money, int year) {
 return money * rate * year;
 };
 // 函数对象 
 Rate r1(rate);
 r1(10000, 2);
 r2(10000, 2);
 auto func1 = [] {
 cout << "hello world" << endl;
 };
 func1();
 return 0;
}

 // lambda
 auto r2 = [rate](double money, int year) {
 return money * rate * year;
 };

三. 新的类功能

3.1 默认的移动构造和移动赋值

在上篇的时候我们就已经初步了解过了由右值引出的移动语义,接下来我们将来相对详细的了解移动构造和赋值

• 原来C++类中,有6个默认成员函数:构造函数/析构函数/拷⻉构造函数/拷⻉赋值重载/取地址重
载/const取地址重载,最后重要的是前4个,后两个⽤处不⼤,默认成员函数就是我们不写编译器
会⽣成⼀个默认的。C++11 新增了两个默认成员函数,移动构造函数和移动赋值运算符重载。
• 如果你没有⾃⼰实现移动构造函数,且没有实现析构函数、拷⻉构造、拷⻉赋值重载中的任意⼀
个。那么编译器会⾃动⽣成⼀个默认移动构造。默认⽣成的移动构造函数,对于内置类型成员会执
⾏逐成员按字节拷⻉,⾃定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调⽤
移动构造,没有实现就调⽤拷⻉构造。
• 如果你没有⾃⼰实现移动赋值重载函数,且没有实现析构函数、拷⻉构造、拷⻉赋值重载中的任意
⼀个,那么编译器会⾃动⽣成⼀个默认移动赋值。默认⽣成的移动构造函数,对于内置类型成员会
执⾏逐成员按字节拷⻉,⾃定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调
⽤移动赋值,没有实现就调⽤拷⻉赋值。(默认移动赋值跟上⾯移动构造完全类似)
• 如果你提供了移动构造或者移动赋值,编译器不会⾃动提供拷⻉构造和拷⻉赋值。

class Person
{
public:
 Person(const char* name = "", int age = 0)
 :_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;
 s4 = std::move(s2);
 return 0;
}

3.2 defult和delete

• C++11可以让你更好的控制要使⽤的默认函数。假设你要使⽤某个默认的函数,但是因为⼀些原因
这个函数没有默认⽣成。⽐如:我们提供了拷⻉构造,就不会⽣成移动构造了,那么我们可以使⽤
default关键字显⽰指定移动构造⽣成。
• 如果能想要限制某些默认函数的⽣成,在C++98中,是该函数设置成private,并且只声明补丁已,
这样只要其他⼈想要调⽤就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语
法指⽰编译器不⽣成对应函数的默认版本,称=delete修饰的函数为删除函数。

class Person
{
public:
 Person(const char* name = "", int age = 0)
 :_name(name)
 , _age(age)
 {}
 Person(const Person& p)
 :_name(p._name)
 ,_age(p._age)
 {}
 Person(Person&& p) = default;
 
 //Person(const Person& p) = delete;
private:
 bit::string _name;
 int _age;
};
int main()
{
 Person s1;
 Person s2 = s1;
 Person s3 = std::move(s1);
 return 0;
}

3.3 final和override

final关键字用于指定一个类不能被继承,或者一个虚函数不能在派生类中被重写。

override关键字用于明确指示一个派生类成员函数是对基类虚函数的重写。

3.4 STL中⼀些变化

• 下图1圈起来的就是STL中的新容器,但是实际最有⽤的是unordered_map和unordered_set。
在这里插入图片描述

• STL中容器的新接⼝也不少,最重要的就是右值引⽤和移动语义相关的push/insert/emplace系列
接⼝和移动构造和移动赋值,还有initializer_list版本的构造等,这些前⾯都讲过了,还有⼀些⽆关
痛痒的需要时查查⽂档即可。
• 容器的范围for遍历

四 包装器

包装器类似于函数指针不过更为简洁和便于使用

4.1. function

• std::function 是⼀个类模板,也是⼀个包装器。 std::function 的实例对象可以包装存储其他的可以调⽤对象,包括函数指针、仿函数、 lambda 、 bind 表达式等,存储的可调⽤对象被称为std::function 的⽬标。若std::function 不含⽬标,则称它为空。调⽤空std::function 的⽬标导致抛出std::bad_function_call 异常。
• 以上是 function 的原型,他被定义在头⽂件中。std::function-cppreference.com
• 函数指针、仿函数、 lambda 等可调⽤对象的类型各不相同, std::function 的优势就是统⼀类型,对他们都可以进⾏包装,这样在很多地⽅就⽅便声明可调⽤对象的类型,下⾯的第⼆个代码样例展⽰了 std::function 作为map的参数,实现字符串和可调⽤对象的映射表功能。

#include<functional>
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()
{
 // 包装各种可调⽤对象 
 function<int(int, int)> f1 = f;
 function<int(int, int)> f2 = Functor();
 function<int(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;
 // 包装静态成员函数 
 // 成员函数要指定类域并且前⾯加&才能获取地址 
 function<int(int, int)> f4 = &Plus::plusi;
 cout << f4(1, 1) << endl;
 // 包装普通成员函数 
 // 普通成员函数还有⼀个隐含的this指针参数,所以绑定时传对象或者对象的指针过去都可以 
 function<double(Plus*, double, double)> f5 = &Plus::plusd;
 Plus pd;
 cout << f5(&pd, 1.1, 1.1) << endl;
 function<double(Plus, double, double)> f6 = &Plus::plusd;
 cout << f6(pd, 1.1, 1.1) << endl;
 cout << f6(pd, 1.1, 1.1) << endl;
 function<double(Plus&&, double, double)> f7 = &Plus::plusd;
 cout << f7(move(pd), 1.1, 1.1) << endl;
 cout << f7(Plus(), 1.1, 1.1) << endl;
 return 0;
}

bind

std::bind 的基本语法如下:

auto new_callable = std::bind(function, arg1, arg2, …, argN);

. function 是你想要绑定的函数或可调用对象。
. arg1, arg2, …, argN 是你想要预先绑定到 function 的参数。这些参数可以是具体的值,也可以是占位符 _1, _2, …(这些占位符定义在 中,表示在调用新函数对象时应该提供的参数)。

#include <functional>  
#include <iostream>  
  
int add(int a, int b) {  
    return a + b;  
}  
  
int main() {  
    // 使用 std::bind 创建一个新的可调用对象,它预先绑定了 add 的第一个参数为 5  
    auto bound_add = std::bind(add, 5, std::placeholders::_1);  
  
    // 调用 bound_add,传入第二个参数(因为第一个参数已经被绑定为 5)  
    std::cout << bound_add(10) << std::endl; // 输出 15  
  
    return 0;  
}

总结

以上便是c++11的部分内容,其中仍有诸多不足之处,望能看到总结处的小伙伴见谅。

标签:11,下篇,函数,int,c++,return,参数,捕捉,lambda
From: https://blog.csdn.net/make_day_day_up/article/details/143362258

相关文章

  • 【软考】系统架构设计师-2011年下半年上午综合知识真题及答案
    全国计算机技术与软件专业技术资格(水平)考试高级系统架构设计师2011年下半年上午试卷 综合知识试题一 操作系统为用户提供了两类接口:操作一级和程序控制一级的接口,以下不属于操作一级的接口是( )。A.操作控制命令  B.系统调用  C.菜单 D.窗口试题二 (第......
  • 学生管理系统(C++)
    #include<iostream>#include<vector>#include<fstream>#include<string>#include<sstream>#include<algorithm>usingnamespacestd;structStudent{std::stringname;intid;intage;......
  • 【NOI】C++函数入门二(自定义函数)
    文章目录前言一、概念1.导入1.1首先什么是函数呢?2.函数分类3.为什么要定义函数呢?4.函数结构5.函数使用注意事项二、例题讲解问题:1137-纯粹素数问题:1258-求一个三位数问题:1140-亲密数对问题:1149-回文数个数三、总结四、感谢前言在这一章节中,我们将深入探......
  • C++学习笔记
    一、从C转向C++1.1、使用const和inline而不#define使用constconstintm=10;intn=m;上述代码在C中,编译器会先到m的内存中取出数据,再赋值给n;但在C++中,会直接将10赋值给n。C++的常量更类似于#define,是一个替换过程。#define经常不被认为是语言的一部分。define本......
  • 11.3 学习日志
    今天把tomcat插件弄好了找到了idea一直连接不上我的数据库的原因然后复习了一下隐式转换和强制转换packagetxt;publicclasstest{publicstaticvoidmain(String[]args){inta=2;doubleb=6.9;c=a+b;}}c为double类型;小向大转换;byteshortchar在运算时都会先变......
  • MT1411-MT1420 码题集 (c 语言详解)
    目录        MT1411·顺时针旋转数组        MT1412·合并        MT1413·并集        MT1414·数组的交集        MT1415·大小相同        MT1416·最长子数组        MT1417·连续子序列        ......
  • 华为OD机试-E卷,100分 - 最小的调整次数特异性双端队列Java & Python& JS & C++ & C
    最新华为OD机试题目描述有一个特异性的双端队列,该队列可以从头部或尾部添加数据,但是只能从头部移出数据。小A依次执行2n个指令往队列中添加数据和移出数据。其中n个指令是添加数据(可能从头部添加、也可能从尾部添加),依次添加1到n;n个指令是移出数据。现在要求移除数据的顺......
  • 华为OD机试-E卷100分 -货币单位换算Java & Python& JS & C++ & C
    最新华为OD机试题目描述记账本上记录了若干条多国货币金额,需要转换成人民币分(fen),汇总后输出。每行记录一条金额,金额带有货币单位,格式为数字+单位,可能是单独元,或者单独分,或者元与分的组合。要求将这些货币全部换算成人民币分(fen)后进行汇总,汇总结果仅保留整数,小数部分舍弃......
  • C++中的内联函数:深入解析与应用
    C++中的内联函数:深入解析与应用在C++编程中,内联函数(InlineFunction)是一种优化手段,旨在通过在编译时将函数调用替换为函数体本身,以减少函数调用的开销,从而提高程序的执行效率。内联函数的使用需要谨慎,因为它虽然能带来性能上的提升,但也可能导致代码膨胀和编译时间增加。本......