如何自己做网站模版,做企业网站的费用挂什么科目,正能量软件不良网站直播,都用什么软件做网站C进阶#xff1a;C11(列表初始化、右值引用与移动构造移动赋值、可变参数模版…Args、lambda表达式、function包装器)
今天接着进行语法方面知识点的讲解 文章目录 1.统一的列表初始化1.1#xff5b;#xff5d;初始化1.2 initializer_listpair的补充 2.声明相关关键字2.1a…C进阶C11(列表初始化、右值引用与移动构造移动赋值、可变参数模版…Args、lambda表达式、function包装器)
今天接着进行语法方面知识点的讲解 文章目录 1.统一的列表初始化1.1初始化1.2 initializer_listpair的补充 2.声明相关关键字2.1auto2.2decltype 3.右值引用和移动语义3.1左值与右值3.2左值引用与右值引用3.3右值引用的场景与意义移动构造移动赋值 引用性质与结论万能引用、完美转发 4.新的类功能4.1默认构造函数4.2关键字default与delete 5.可变参数模板展开参数包容器的emplace_back()和insert 6. lambda表达式6.1引入6.2lambda表达式 7.function包装器成员函数的包装 1.统一的列表初始化
1.1初始化
在C98中标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。
C11扩大了用大括号括起的列表(初始化列表)的使用范围使其可用于所有的内置类型和用户自定义的类型使用初始化列表时可添加等号()也可直接省略
创建对象时也可以使用列表初始化方式调用构造函数初始化 这样做的目的就是 一切皆可用{}初始化列表初始化 #includeiostreamusing namespace std;struct Point
{int _x;int _y;
};int main()
{int a1 1;int a2 { 1 };int a3{ 1 };//这些都能初始化int a4(1);int a5 int(1);//这两个是模版支持的基本类型int构造和拷贝构造int array1[] { 1, 2, 3, 4, 5 };int array2[]{ 1, 2, 3, 4, 5 };//也能省略Point p1 { 1, 2 };Point p2 { 1 };// _y默认初始化成0了return 0;
}本质
int main()
{Point p1 { 1, 2 };//本质就是构造 拷贝构造 - 优化直接构造//相应的构造函数支持隐式类型转换产生的临时对象是Point类型构造出来的Point* pp new Point[2]{ {1,2},{2,3} };//这样的的意义比较大return 0;
}1.2 initializer_list
int main()
{Point p1 { 1, 2 };vectorint v { 1,2,3,4 };//这里两个是一样的吗//不一样前者数量限定死了后者还可以随便加减return 0;
}那这个initializer_list是何方神圣呢C11里新增的类型 在C中初始化列表Initializer list提供了一种方便的方式来使用一组值对对象进行初始化。std::initializer_list是C标准库提供的一个模板类 当我们使用初始化列表初始化对象时编译器会自动从用大括号{}括起来的值列表构造一个std::initializer_list对象。这样你就可以使用std::initializer_list对象来访问列表中的值。 举个例子在代码片段auto il { 10, 20, 30 };中一个std::initializer_listint对象il被创建其中包含值10、20和30。这里使用auto关键字让编译器推断il的类型这种情况下类型会是std::initializer_listint。 需要注意的是std::initializer_list并不会隐式定义因此你需要包含initializer_list头文件才能访问它即使你在隐式使用它。这个头文件提供了与初始化列表相关的必要定义。 所以vector v { 1,2,3,4 }; 相当于右侧就是一个initializer_list的对象隐式类型转换构造出一个vector然后拷贝构造 在语句vectorint v { 1, 2, 3, 4 };中右侧的{ 1, 2, 3, 4 }就是一个初始化列表对象std::initializer_listint。这个初始化列表对象会隐式地进行类型转换构造出一个std::vectorint对象然后通过拷贝构造函数将这个std::vectorint对象赋值给变量v。 mapstring, string dict2 { {sort, 排序}, {string, 字符串} };pair的补充
int main()
{pairconst char*, const char* kv3(sort, 排序);pairconst string, string kv4(kv3);//明明是不同类型但是却可以初始化return 0;
}2.声明相关关键字
2.1auto
在C11标准中引入了auto关键字它可以用于声明变量时让编译器自动推断变量的类型。使用auto关键字可以简化代码减少重复的类型声明提高代码的可读性和可维护性。
自动类型推断: 当使用auto关键字声明变量时编译器会根据变量的初始化表达式推断出变量的类型
int main()
{mapstring, string dict2 { {sort, 排序}, {string, 字符串} };auto it2 dict2.begin();mapstring, string ::iterator it2 dict2.begin();//这样看是不是auto真香啊return 0;
}2.2decltype
decltype 是 C11 中引入的一个关键字用于获取表达式的类型(推断类型)。它通常与 auto 结合使用用于声明变量的类型或者作为模板参数推断的一部分。推导完类型后还能用来定义变量
const修饰变量本身时在使用decltype获取时会去掉const
获取表达式类型: decltype 可以获取表达式的类型包括变量、函数返回值、表达式等。例如
int x 10;
decltype(x) y 20; // y的类型为int与x相同 这里decltype(x)就是一个类型3.右值引用和移动语义
3.1左值与右值 左值是一个表示数据的表达式(如变量名或解引用的指针)我们可以获取它的地址可以对它赋值左值可以出现赋值符号的左边右值不能出现在赋值符号左边。定义时const修饰符后的左值不能给他赋值但是可以取它的地址。左值引用就是给左值的引用给左值取别名右值也是一个表示数据的表达式如字面常量、表达式返回值函数返回值(这不能是左值引用返回)等等右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边右值不能取地址。右值引用就是对右值的引用给右值取别名右值可以进一步分为纯右值prvalue和将亡值xvalue。这两种右值的区别在于它们的生命周期和可修改性。 纯右值prvalue内置类型的右值纯右值通常是表达式的结果或字面常量 将亡值xvalueexpiring value自定义类型的右值将亡值是指一个即将被销毁的值它具有“将亡的”特性。通常是临时对象、匿名对象 int fun1()
{static int a 1;return a;
}int fmin(int a,int b)
{if (a b)return a;elsereturn b;
}int main()
{int a 0;int* pa a;int ret fun1();//这里apafun1的返回值都是左值都能取地址// 以下几个都是常见的右值10;a ret;fmin(a, ret);return 0;
}在函数返回一个临时对象时编译器会将该临时对象视为一个右值rvalue。 右值是一个临时的、无法被修改的值因此在传值返回时编译器会将该临时对象隐式地添加 const 修饰符使其成为一个常量对象 3.2左值引用与右值引用 我们之前使用的引用都是左值引用那么现在右值引用就是 // 以下几个都是对右值的右值引用int r1 10;double r2 a ret;double r3 fmin(a, ret);左值引用是给左值取别名不能给右值引用取别名。但是const 左值引用可以给右值取别名 右值引用不能给左值取别名但是右值引用可以给move以后的左值取别名 move其实就是移动语义move后的左值会变成将亡值
int main()
{// 左值引用只能引用左值不能引用右值。int a 10;int ra1 a; // const左值引用既可引用左值也可引用右值。const int ra2 10;const int ra3 a;//----------------------------------------------------------------// 右值引用只能右值不能引用左值。int r1 10;// 右值引用可以引用move以后的左值move会返回右值引用int r2 std::move(a);return 0;
}3.3右值引用的场景与意义 我们先来回顾一下左值引用的意义——解决了什么问题 传参的拷贝问题在函数调用时如果参数是通过值传递传值的方式传递的会导致参数的拷贝构造函数被调用增加了额外的开销。通过使用左值引用作为函数参数可以避免不必要的拷贝构造提高程序的性能和效率。 部分传返回值的问题非局部对象在函数返回一个临时对象时如果返回类型是一个对象而不是引用或指针会导致拷贝构造函数被调用产生额外的开销。通过使用左值引用作为返回类型可以避免不必要的拷贝构造提高程序的性能。 但是如果我们要返回一个局部对象呢就只能使用传值返回一旦返回一个巨大的容器对象之类的那开销是非常大的。 此时右值引用的意义之一就是解决局部对象(出了作用域就销毁的对象)返回的拷贝问题 函数返回局部对象的问题 对于内置类型如 int、double、char 等因为内置类型的赋值和返回通常是按值传递的而不是按引用传递。这意味着内置类型的值会被直接复制或返回而不需要调用拷贝构造函数。 在返回内置类型时编译器会进行优化避免不必要的拷贝操作直接将返回值传递给调用者或存储在临时变量中 将局部变量作为返回值返回编译器会创建一个临时变量临时对象来存储这个返回值从而避免返回一个指向已经被销毁内存的引用 编译器会调用拷贝构造函数来初始化临时变量。拷贝构造函数的目的是将一个对象的值复制到另一个对象中以确保临时变量拥有正确的值 那这个临时变量存在哪里呢 移动构造
问题的提出 mystring::string to_string(int value){bool flag true;if (value 0){flag false;value 0 - value;//负数变正数}mystring::string str;//这里是定义了一个局部的stringwhile (value 0){int x value % 10;value / 10;str (0 x);}if (flag false){str -;}std::reverse(str.begin(), str.end());return str;//最后返回这个局部的string不能返回左值引用。目前采取的是传值返回//核心问题是出了作用域就销毁了返回什么引用都不行}解决问题 // 拷贝构造 -- 左值//一开始只有这个拷贝构造时因为const 左值引用能给右值取别名//所以左值走这个右值也走这个string(const string s):_str(nullptr){cout string(const string s)--正常拷贝构造 endl;_str new char[s._capacity 1];strcpy(_str, s._str);_size s._size;_capacity s._capacity;}//现在我们为右值特地编写一个构造函数右值引用就走这个了// 移动构造 -- 右值(将亡值)string(string s){cout string(string s)-- 移动拷贝 endl;//方便观察结果swap(s);}这里也能证明编译器进行了优化 移动构造移动构造函数是 C11 引入的一个重要特性用于实现对象的移动语义。通过移动构造函数可以将一个临时对象右值引用的资源如堆上分配的内存“移动”给另一个对象而不是进行昂贵的拷贝操作。这可以提高程序的性能和效率 浅拷贝的类不需要移动构造深拷贝的类才需要移动构造 深拷贝就说明我们进行了涉及到动态内存分配和释放那么如果进行每次返回局部变量都进行内容拷贝代价极大 而浅拷贝没有涉及到动态内存分配和释放那么移动构造函数可能并不是必需的因为浅拷贝只是简单地复制值不存在资源的所有权转移 移动赋值
问题提出 此时str还是左值那么如果我们move后使之变为右值将亡值呢 解决问题 // 赋值重载string operator(const string s){cout string operator(string s) -- 深拷贝 endl;string tmp(s);swap(tmp);return *this;}//移动赋值string operator(string s)//接收右值{swap(s);//移动将亡值的资源并且把不要空间给将亡值让将亡值帮着释放return *this;}此时为了处理右值我们写出移动赋值的函数。直接进行资源的交换还能顺便让将亡值帮着释放 引用性质与结论万能引用、完美转发 对于自定义类型左值我们最好不要随便去move有可能move后里面的数据就被转移走了 右值被右值引用以后右值引用本身的属性是左值 为什么这样设计 我们右值引用是为了解决返回局部变量的拷贝问题具体实现是进行资源的转换。那么如果右值引用本身还是右值不能被改变那还怎么进行资源的转移 const 右值 右值引用后不能改变
万能引用是 C11 中引入的一种引用类型用于实现泛型编程时处理模板类型参数的值类别左值或右值。
在 C11 中引入了右值引用Rvalue Reference其语法为 T其中 T 是类型。右值引用主要用于移动语义和完美转发。当右值引用绑定到一个右值时可以实现移动语义避免不必要的对象拷贝。但右值引用也可以绑定到一个左值这时就无法区分左值和右值。
为了解决这个问题C11 引入了万能引用的概念也称为转发引用Forwarding Reference。万能引用的语法是 T其中 T 是模板类型参数。当万能引用绑定到一个右值时它被推导为右值引用当绑定到一个左值时它被推导为左值引用。这样万能引用可以根据传入的参数的值类别来保持其原有的值类型。
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; }//这是模版那么模版就应该能自己推演啊
templatetypename T
void test(T t)
{cout void test(T t) endl;Fun(t);
}int main()
{test(10); // 右值cout ---------------------------------------------------- endl;int a;test(a); // 左值cout ---------------------------------------------------- endl;test(std::move(a)); // 右值cout ---------------------------------------------------- endl;return 0;
}这里我们使用move也不行——不确定是左值还是右值。这里就能使用完美转发
完美转发是 C11 引入的一个特性用于在函数模板中保持参数的值类别左值或右值和常量性同时将参数原样传递给另一个函数。完美转发通常与模板和引用折叠相关联并在实现泛型代码时非常有用。 引用折叠 引用折叠是 C11 中的一个规则用于确定引用的最终类型。在模板中使用引用时引用可能会发生折叠最终得到左值引用或右值引用。引用折叠规则T 折叠为 TT 折叠为 TT 和 T 都折叠为 T。 std::forward std::forward 是一个模板函数用于在函数模板中完美转发参数。std::forward 接受一个参数和参数的类型并根据参数的值类别左值或右值进行转发。当传递左值时std::forward 将返回左值引用当传递右值时std::forward 将返回右值引用。 4.新的类功能
4.1默认构造函数
之前我们学习的C类中有6个默认成员函数 构造函数 析构函数 拷贝构造函数 拷贝赋值重载 取地址重载 const 取地址重载 现在就新增了两个我们上面才讲的移动构造和移动赋值 如果你没有自己实现移动构造函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝浅拷贝 自定义类型成员则需要看这个成员是否实现移动构造如果实现了就调用移动构造没有实现就调用拷贝构造。 如果你没有自己实现移动赋值重载函数且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数对于内置类型成员会执行逐成员按字节拷贝自定义类型成员则需要看这个成员是否实现移动赋值如果实现了就调用移动赋值没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似) 如果你提供了移动构造或者移动赋值编译器不会自动提供拷贝构造和拷贝赋值
4.2关键字default与delete
强制生成默认函数的关键字default:
C11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数但是因为一些原因这个函数没有默认生成。比如我们提供了拷贝构造就不会生成移动构造了那么我们可以使用default关键字显示指定移动构造生成
禁止生成默认函数的关键字delete:
如果能想要限制某些默认函数的生成在C98中是该函数设置成private并且只声明补丁已这样只要其他人想要调用就会报错。在C11中更简单只需在该函数声明加上delete即可该语法指示编译器不生成对应函数的默认版本称delete修饰的函数为删除函数。经常用来防止类可以被拷贝。成员函数声明尾部加上delete表示该成员函数被禁掉编译器会删除这样的类成员函数
class Person
{
public:Person(const char* name , int age 0):_name(name), _age(age){}Person(const Person p) delete;//禁止生成Person(Person p) default;//强制生成
private:string _name;int _age;
};一般也可不加上参数名 5.可变参数模板 早在c语言里的printf函数就有可变参数的概念我们能随意传入不同数量想参数。虽然底层很难但是我们用起来舒服 可变参数模板是 C11 中引入的一个特性允许函数模板接受任意数量的参数。通过可变参数模板可以实现灵活的函数接口处理不定数量的参数类似于可变参数函数如 printf的功能。
在 C 中可变参数模板通常使用模板参数包template parameter pack来实现。模板参数包允许在模板参数列表中接受任意数量的参数并通过展开expansion来处理这些参数。
一个基础的模版
// Args是一个模板参数包args是一个函数形参参数包
// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。
template class ...Args//不一定非要叫Args
void ShowArgs(Args... args)
{}上面的参数args前面有省略号所以它就是一个可变模版参数我们把带省略号的参数称为“参数包”它里面包含了0到NN0个模版参数。 我们无法直接获取参数包args中的每个参数的只能通过展开参数包的方式来获取参数包中的每个参数这是使用可变模版参数的一个主要特点也是最大的难点即如何展开可变模版参数。 我们可以使用sizeof...(args)来得到有几个参数
展开参数包
递归函数方式展开参数包使用编译时解析编译时递归
void _ShowArgs()//编译时递归的结束条件
{cout endl;
}template class T, class ...Args
void _ShowArgs(const T t, Args... args)//把第一个参数拿出来
{cout t endl;_ShowArgs(args...);
}// Args是一个模板参数包args是一个函数形参参数包
// 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。
template class ...Args
void ShowArgs(Args... args)
{_ShowArgs(args...);
}int main()
{ShowArgs(1, abc, c);return 0;
}容器的emplace_back()和insert emplace_back() 是 C 容器类如 std::vector, std::deque, std::list 等提供的一个成员函数用于在容器的末尾直接构造一个新元素而不是先创建一个临时对象再拷贝或移动到容器中。这样可以避免不必要的对象创建和拷贝操作提高代码的性能和效率。
emplace_back() 的优势
避免不必要的对象创建和拷贝使用 emplace_back() 直接在容器中构造对象避免了先创建临时对象再拷贝或移动的开销。更高效的内存管理emplace_back() 可以在容器的末尾直接构造对象减少了不必要的内存分配和释放操作。支持完美转发emplace_back() 可以完美转发参数给对象的构造函数保留了原始参数的类型和属性。直接构造函数的前提是直接传入参数而不是现成的对象或者匿名对象
与 push_back() 的区别
push_back() 接受一个对象的副本拷贝或移动而 emplace_back() 直接在容器中构造对象。emplace_back() 通常比 push_back() 更高效特别是在构造对象开销较大时。
class Date
{
public:Date(int year, int month, int day):_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 200;int _month 1;int _day 1;
};int main()
{std::listDate lt1;lt1.push_back({ 2024,3,30 });cout endl;//支持这个因为隐式类型转换构造出一个节点后再push//lt1.emplace_back({ 2024,3,30 });// 不支持。因为底层是模版根据这个推出不data类// // 这样是可以的可以自己推导lt1.emplace_back(2024, 3, 30);cout ---------------------------------------------------- endl;Date d1(2023, 1, 1);lt1.push_back(d1);cout endl;lt1.emplace_back(d1);cout ---------------------------------------------------- endl;lt1.push_back(Date(2023, 1, 1));cout endl;lt1.emplace_back(Date(2023, 1, 1));return 0;
}对于使用 emplace_back() 或者 emplace 系列函数来直接在容器中构造对象的情况需要传入构造函数所需的参数而不是现成的对象或者匿名对象。 这是因为 emplace_back() 或者 emplace 系列函数是通过完美转发参数给构造函数来在容器中构造对象的 6. lambda表达式
6.1引入
之前我们想要对自定义类型进行排序的话要自己给出比较方法的仿函数
#includealgorithm
struct Good
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Good(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};struct ComparePriceLess
{bool operator()(const Good gl, const Good gr){return gl._price gr._price;}
};struct ComparePriceGreater
{bool operator()(const Good gl, const Good gr){return gl._price gr._price;}
};int main()
{vectorGood v { { apple, 2.1, 5 }, { banana, 3, 4 }, { orange, 2.2,3 }};sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater());//这里我们想要比较就只能自己给出仿函数
}我们现在给出是按照价格排序如果我们想要按照名称或者数量排序呢那又要写额外的仿函数那就有点麻烦了 每次为了实现一个algorithm算法都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名这些都给编程者带来了极大的不便。因此在C11语法中出现了Lambda表达式 6.2lambda表达式
在C中Lambda表达式是一种匿名函数本质是一个局部的匿名函数对象可以在需要函数对象的地方使用例如作为参数传递给标准算法函数。Lambda表达式的一般形式如下
[capture-list](parameters) mutable - return-type {// Lambda函数体// 可以使用捕捉列表中的变量和参数列表中的参数return expression; // 可选
}下面是Lambda表达式的各个部分说明 捕捉列表 [capture-list]捕捉列表用于捕捉上下文中的变量供Lambda函数使用。捕捉列表可以为空也可以包含以下内容 []表示不捕捉任何变量。[]通过引用捕捉所有外部变量。[]通过值捕捉所有外部变量。[var]通过值捕捉特定变量 var。[var]通过引用捕捉特定变量 var。 参数列表 (parameters)与普通函数的参数列表一致可以省略参数列表即使不需要参数传递。 mutable可选关键字用于取消Lambda函数的常量性。如果Lambda函数需要修改捕捉的变量则需要使用 mutable 关键字。 返回值类型 - return-type用于指定Lambda函数的返回值类型可以省略编译器会根据返回语句进行推导一般情况都不写。 函数体 { statement }Lambda函数体包含了Lambda函数的实际逻辑。在函数体内可以使用捕捉的变量和参数。
示例
int main()
{vectorGood v { { apple, 2.1, 5 }, { banana, 3, 4 }, { orange, 2.2,3 }};auto add [](int a, int b) {return a b; };cout add(1, 2) endl;auto swap1 [](int a, int b)-void {int tmp a;a b;b tmp;};auto print [] {cout auro print endl;};//这个就是能省的都省了当然函数体里面也能什么都不写print();//调用上面这个return 0;
}学会了基本使用后我们能来解决上面的问题
#includealgorithm
struct Good
{string _name; // 名字double _price; // 价格int _evaluate; // 评价Good(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){}
};int main()
{vectorGood v { { apple, 2.1, 5 }, { banana, 3, 4 }, { orange, 2.2,3 } };sort(v.begin(), v.end(), [](const Good g1, const Good g2) {return g1._price g2._price;});sort(v.begin(), v.end(), [](const Good g1, const Good g2) {return g1._price g2._price;});sort(v.begin(), v.end(), [](const Good g1, const Good g2) {return g1._evaluate g2._evaluate;});return 0;
}int main()
{int x 1, y 2;// 传引用捕捉auto swap [x, y]{int tmp x;x y;y tmp;};swap();cout x endl;cout y endl;int m 3, n 4;// 传值捕捉当前域的所有对象auto func1 [] {return x y * m - n;};cout func1() endl;// 传引用捕捉当前域的所有对象auto func2 [] {x;m;return x y * m - n;};cout func2() endl;cout x endl;cout m endl;// 传引用捕捉当前域的所有对象对个别对象传值捕捉auto func3 [, n] {x;m;// n; 不行return x y * m - n;};cout func3() endl;cout x endl;cout m endl;//----------------------------------auto DateLess [](const Date* p1, const Date* p2){return p1 p2;};//只能用auto来接收这样也表明不能得到具体的类型。要结合decltype使用priority_queueDate*, vectorDate*, decltype(DateLess) p1(DateLess);return 0;
}7.function包装器
在C中std::function是一个通用的函数包装器它可以用来存储、复制和调用任何可调用对象包括函数指针、函数对象、Lambda表达式等。std::function提供了一种统一的接口使得可以将不同类型的可调用对象存储在同一个对象中并且可以通过该对象进行调用。
C中的function本质是一个类模板function可以封装他们目标是统一类型统一后我们能传给各种容器使用函数指针的话类型复杂、仿函数的类型不同、Lambda表达式没有类型。三者各有各的问题。
std::function的一般形式如下
// 类模板原型如下
template class T function; // undefined
template class Ret, class... Args
class functionRet(Args...);
//模板参数说明
//Ret: 被调用函数的返回类型
//Args…被调用函数的形参functionreturn_type(parameters) func;return_type是函数的返回类型parameters是函数的参数列表。通过std::function的模板参数可以指定存储的可调用对象的类型。
存储可调用对象std::function可以存储各种可调用对象如函数指针、函数对象、Lambda表达式等。调用函数通过operator()运算符可以调用std::function对象所包装的可调用对象就像调用普通函数一样。空对象如果std::function未与任何可调用对象关联即为空对象调用空对象会引发未定义行为。因此在使用前需要确保std::function对象不为空。
#includefunctionaldouble fun1(double i)
{return i * 2;
}
struct Function
{double operator()(double f){return f / 3;}
};int main()
{// 函数指针functiondouble(double) fc1 fun1;fc1(1.1);// 函数对象functiondouble(double) fc2 Function();fc2(1.1);// lambda表达式functiondouble(double) fc3 [](double d)-double { return d / 4; };fc3(1.1);return 0;
}成员函数的包装
class Plus
{
public:static int plus_static(int a, int b)//静态成员函数{return a b;}double plus(double a, double b)//普通成员函数{return a b;}
};int main()
{//包装静态的functionint(int, int) fun1 Plus::plus_static;//注意要指明类域cout fun1(1, 1) endl;//包装普通functiondouble(Plus,double, double) fun2 Plus::plus;//注意要指明类域functiondouble(Plus*,double, double) fun3 Plus::plus;//这两种都行cout fun1(1, 1) endl;return 0;
}非静态成员函数需要对象的指针或者对象去进行调用 好了内容是真不少啊下面就带来c里面的异常了