三、绑定器和函数对象、lambda表达式
文章目录
- 三、绑定器和函数对象、lambda表达式
- 3.1模板的完全特例化和非完全(部分)特例化
- 1.完全特例化和非完全(部分)特例化
- 2.模板的实参推演
- 3.2 C++ STL中的绑定器
- bind1st
- bind2nd
- 自己实现一个bind1st
- 3.3 C++11从Boost库中引入了bind和function函数对象机制
- 1.function函数对象类型的应用示例(function基础)
- 2.fucntion函数对象类型的实现原理
- 3.bind
- 4.bind 和 function实现线程池
- 3.4 lambda表达式 底层依赖函数对象机制实现的
- 1.lambda概述
- 2.lambda表达式的语法
- lambda匿名函数中的[外部变量]
- 3.lambda的应用实践
- 1.泛型算法之中
- 2.既然lambda只能用在语句中,如果想跨语句使用之前定义好的lambda表达式怎么办?有什么类型表达lambda?
3.1模板的完全特例化和非完全(部分)特例化
1.完全特例化和非完全(部分)特例化
template<typename T>
class Vector
{
public:
Vector () { cout << "call Vector template init" << endl; }
};
// 下面这个是对char*类型提供的完全特例化版本
//1.必须得有上面那个才能提供下面这个,光下面这个也不行
//2. "<>"这是语法不能省略
template<>
class Vector<char*>
{
public:
Vector () { cout << "call Vector<char*> init" << endl; }
};
//针对指针类型提供的部分特例化版本
template<typename T>//我们并不知道是哪个类型的指针,所以还是要写typename T
class Vector<T*>
{
public:
Vector () { cout << "call Vector<T*> init" << endl; }
};
//针对函数指针类型(有返回值,有两个形参变量的函数)提供的部分特例化版本
template<typename R,typename A1,typename A2>
class Vector<R(*)(A1,A2)>
{
public:
Vector () { cout << "call Vector<R(*)(A1,A2)> init" << endl; }
};
//完全特例化
template<>
class Vector<int(*)(int,int)>
//部分特例化更灵活一点
//函数类型部分特例化
template<typename R,typename A1,typename A2>
class Vector<R(A1,A2)>
{
public:
Vector () { cout << "call Vector<R(A1,A2)> init" << endl; }
};
int sum(int a,int b) {return a+b;}
int main()
{
Vector<int> vec1;//从原模板进行实例化
Vector<char *> vec2;//使用完全特例化版本
Vector<int *> vec3;//使用针对指针的部分特例化版本
Vector<int(*)(int,int)>vec4;//使用针对指针的特例化版本 这个类型相当于上面sum函数类型(函数指针),只是同一个类型,不是指sum函数
Vector<int(int,int)>vec4;//这是函数类型,不是函数指针类型,匹配的是函数类型的模板进行实例化
//函数类型
typedef int (*PFUNC1) (int, int);
PFUNC1 pfunc1 = sum;
cout << pfunc1(10, 20) << endl;
//函数指针类型
typedef int PFUNC2 (int, int);
PFUNC2 *pfunc2 = sum;
cout << (*pfunc2)(10, 20) << endl;
//注意区分两者
return 0;
}
先看有没有完全特例化,没有看部分特例化,最后看原模板
2.模板的实参推演
typeid().name用来得到传入参数的类型
向上面一样,我们如果得到的T是
int (*)(int,int)或者int(int,int)
那完全没什么作用,就只是知道了,而现在可以通过实参推演,获得各个部分是什么类型,以下面代码为例
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
#include<typeinfo>
using namespace std;
//获得普通类型
template<typename T>
void func(T a)
{
cout << typeid(T).name() << endl;
}
int sum(int a, int b) { return a + b; }
template<typename R,typename A1,typename A2>//指针对函数指针
void func2(R (*a)(A1,A2))
{
cout << typeid(R).name() << endl;
cout << typeid(A1).name() << endl;
cout << typeid(A2).name() << endl;
}
//int,int,int
class test
{
public:
int sum(int a, int b) { return a + b; }
};
template<typename R, typename T,typename A1, typename A2>//针对类成员函数
void func3(R(T::*a)(A1, A2))
{
cout << typeid(R).name() << endl;
cout << typeid(T).name() << endl;
cout << typeid(A1).name() << endl;
cout << typeid(A2).name() << endl;
}
//int,class test,int,int
//可以用这些进行变量定义
int main()
{
func(10);
func("aaa");
func(sum);
cout << "----" << endl;
func2(sum);
cout << "----" << endl;
func3(&test::sum);
return 0;
}
运行结果:
从结果可以看出,我们可以获得各个类型
3.2 C++ STL中的绑定器
bind1st和bind2nd是C++标准库中的两个函数适配器,它们的主要作用是将一个二元函数对象(即接受两个参数的函数对象)转换为一元函数对象(即接受一个参数的函数对象)。这两个函数适配器的区别主要在于它们绑定的是二元函数对象的哪一个参数。
只能用于二元
bind1st
- 功能:bind1st函数接受一个二元函数和一个值,返回一个新的函数对象。这个新的函数对象将二元函数的第一个参数绑定为给定的值,因此调用时只需要提供第二个参数。
- 使用场景:当你希望将一个二元函数的第一个参数固定为某个值时,可以使用bind1st。这样,你就可以得到一个一元函数,其行为类似于原二元函数但第一个参数已被绑定。
bind2nd
- 功能:与bind1st类似,bind2nd函数也接受一个二元函数和一个值,但返回的新函数对象将二元函数的第二个参数绑定为给定的值。因此,调用时只需要提供第一个参数。
- 使用场景:当你希望将一个二元函数的第二个参数固定为某个值时,可以使用bind2nd。这样,你也可以得到一个一元函数,但其行为是原二元函数且第二个参数已被绑定。
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
using namespace std;
void printvec(vector<int>& v)
{
for (auto c : v)
cout << c << " ";
cout << endl;
}
int main()
{
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20; i++)
{
vec.push_back(rand() % 100 + 1);
}
printvec(vec);
//从小到大
sort(vec.begin(), vec.end());
printvec(vec);
//从大到小
sort(vec.begin(), vec.end(),greater<int>());
printvec(vec);
//greater a>b 从大到小
//less a<b 从小到大
/*bind绑定器
把70按顺序插入到vec容器中 找第一个小于70的数字,那只传入一个参数,就没办法用gerater或者less了
所以可以用绑定器 绑定器 + 二元函数对象 => 一元函数对象
bind1st:+ greater bool operator()(70,const _Ty& _Right)
bind2nd:+ less bool operator()(const _Ty& _Left,70)
*/
auto it1 = find_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70));
if (it1 != vec.end())
vec.insert(it1, 70);
printvec(vec);
auto it2 = find_if(vec.begin(), vec.end(), bind2nd(less<int>(), 60));
if (it2 != vec.end())
vec.insert(it2, 60);
printvec(vec);
return 0;
}
自己实现一个bind1st
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
using namespace std;
template<typename Iterator,typename Compare>
Iterator my_find_if(Iterator first, Iterator last, Compare comp)
{
for (; first != last; first++)
{
if (comp(*first))//comp.operator()(*fist) comp的()重载函数传入参数为*first
{
return first;
}
}
return last;
}
template<typename Compare, typename T>
class _mybind1st
{
public:
_mybind1st(Compare comp,T val):_comp(comp),_val(val){}
bool operator()(const T& second)
{
return _comp(_val, second);
}
private:
Compare _comp;
T _val;
};
template<typename Compare,typename T>
_mybind1st<Compare,T> mybind1st(Compare comp, const T& val)
{
return _mybind1st<Compare, T>(comp, val);
}
void printvec(vector<int>& v)
{
for (auto c : v)
cout << c << " ";
cout << endl;
}
int main()
{
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20; i++)
vec.push_back(rand() % 100 + 1);
printvec(vec);
//从小到大
sort(vec.begin(), vec.end());
printvec(vec);
auto it1 = find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70));
if (it1 != vec.end())
vec.insert(it1, 70);
printvec(vec);
return 0;
}
过程说明:
- 创建
_mybind1st
对象:
当调用mybind1st(greater<int>(), 70)
时,会创建一个_mybind1st<greater<int>, int>
类型的临时对象。这个对象内部存储了greater<int>
的一个实例(作为_comp
成员变量)和整数70
(作为_val
成员变量)。 - 将
_mybind1st
对象传递给my_find_if
:
然后,这个_mybind1st
对象被传递给my_find_if
函数作为comp
参数。 - 在
my_find_if
中调用comp(*first)
:
在my_find_if
的循环中,当调用comp(*first)
时,实际上是在调用_mybind1st
对象的operator()
成员函数。这是因为_mybind1st
对象是一个函数对象,它重载了operator()
以使其表现得像一个函数。 _mybind1st
的operator()
实现:
在_mybind1st
的operator()
中,代码是return _comp(_val, second);
。这里,_comp
是存储的greater<int>
对象,_val
是70
,而second
是*first
(即当前正在检查的元素)。因此,这个调用实际上是在检查当前元素*first
是否小于70
(因为greater<int>
的operator()
检查第一个参数是否大于第二个参数,而这里我们是在用_val
(即70
)作为第一个参数,*first
作为第二个参数)。
补充内容:
greater<int>
是C++标准库中的一个模板类,用于表示两个整数之间的“大于”关系。当实例化greater<int>
时,会得到一个函数对象,该函数对象重载了operator()
,接受两个int
类型的参数,并返回第一个参数是否大于第二个参数的布尔值。
例如:
greater<int> comp;
bool result = comp(5, 3); // result 为 true,因为 5 > 3
3.3 C++11从Boost库中引入了bind和function函数对象机制
1.function函数对象类型的应用示例(function基础)
绑定器,函数对象,lambda表达式 他们只能在一条语句中使用
function作用:
把上面这三个的类型留下来,说得更清楚点就是再给他们一个名字然后方便之后通过调用给的名字来使用函数对象或者lambda的功能。
function基础:
1.用函数类型实例化function
2.通过function调用operator()函数的时候,需要根据函数类型传入相应的参数
具体实例:
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
#include<typeinfo>
using namespace std;
void hello1()
{
cout << "hello world" << endl;
}
void hello2(string str)
{
cout << str << endl;
}
int sum(int a, int b)
{
return a + b;
}
class test
{
public:
void hello2(string str)
{
cout << str << endl;
}
};
int main()
{
//从function的类模板定义处,看到希望用一个函数类型实例化function
function<void()> func1 = hello1;
//1.func1.operator() => hello1 先调用func1的()重载函数,然后调用包装的hello1
func1();
//2.人原来有参数,你写的时候就要加上参数,传入的时候也要传入
function<void(string)> func2 = hello2;
func2("hello hello2");
//有返回值的
function<int(int, int)> func3 = sum;
cout << func3(20, 30) << endl;
//3.lambda的类型保留 注意结尾不要忘了加分号
function<int(int, int)> func4 = [](int a, int b)->int {return a + b; };
cout<<func4(100, 200)<<endl;
//4.成员函数的类型保留
//注意点1:在原来的参数列表要多加一个test*
// 注意点2:调用func5的时候要借助该类对象的指针,这里就构建一个临时对象取地址当做指针来用
function<void(test*, string)> func5 = &test::hello2;
func5(&test(), "call test::hello");
//成员函数指针和普通函数指针不同
//普通指针随便调用就行,但成员函数前面必须要有一个作用域,所以必须依赖一个对象,这也是调用func5要加一个test*的原因
//成员函数一经编译参数都会多一个指向当前类型的this指针
//void (*print)(string str)
//void (test::*print)(striing str)
return 0;
}
结合例子来看:
1.func1.operator() => hello1 先调用func1的()重载函数,然后调用包装的hello1
2.人原来有参数,你写的时候就要加上参数,传入的时候也要传入
3.lambda的类型保留 注意结尾不要忘了加分号
4.成员函数的类型保留
注意点1:在原来的参数列表要多加一个test*
注意点2:调用func5的时候要借助该类对象的指针,这里就构建一个临时对象取地址当做指针来用
-
成员函数指针和普通函数指针不同
普通指针随便调用就行,但成员函数前面必须要有一个作用域,所以必须依赖一个对象,这也是调用func5要加一个test*的原因
成员函数一经编译参数都会多一个指向当前类型的this指针void (*print)(string str) void (test::*print)(striing str)
2.fucntion函数对象类型的实现原理
实例:
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
#include<typeinfo>
using namespace std;
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
//原模板
template<typename Fty>
class myfunction{};
//模板的特例版本 针对hello
template<typename R,typename A1>
class myfunction<R(A1)>
{
public:
using PFUNC = R(*)(A1);
myfunction(PFUNC pfunc):_pfunc(pfunc){}
R operator()(A1 arg)
{
return _pfunc(arg);
}
private:
PFUNC _pfunc;
};
//模板的特例版本 针对sum
template<typename R, typename A1, typename A2>
class myfunction<R(A1,A2)>
{
public:
using PFUNC = R(*)(A1,A2);
myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
R operator()(A1 arg1,A2 arg2)
{
return _pfunc(arg1,arg2);
}
private:
PFUNC _pfunc;
};
int main()
{
myfunction<void(string)> func1 = hello;
func1("hello world");
myfunction<int(int,int)> func2 = sum;
cout<<func2(10, 20) << endl;
return 0;
}
那肯定会觉得,那这得写多少代码才可以写完,但其实不需要。C+11中提供了可变参的类型参数:包(arg…)
可以理解为把你传进入的所有参数,依次一个一个的传入
感兴趣的读者可以去这里看看相关知识点,这里不再赘述。
C++11 新特性 学习笔记-CSDN博客
通过可变参数实现:
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
#include<typeinfo>
using namespace std;
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
template<typename Fty>
class myfunction{};
template<typename R, typename... A>
class myfunction<R(A...)>
{
public:
using PFUNC = R(*)(A...);
myfunction(PFUNC pfunc) :_pfunc(pfunc) {}
R operator()(A... arg)
{
return _pfunc(arg...);//相当于return sum(10,20);
}
private:
PFUNC _pfunc;
};
int main()
{
myfunction<void(string)> func1 = hello;
func1("hello world");
myfunction<int(int,int)> func2 = sum;
cout<<func2(10, 20) << endl;
return 0;
}
可以当做是一个可变参数模板的一个实例进行记忆。
3.bind
bind绑定器返回的也是函数对象
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
#include<typeinfo>
using namespace std;
using namespace placeholders;
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
class test
{
public:
int sum(int a, int b) { return a + b; }
};
int main()
{
//1.bind是函数模板 可以自动推演模板类型参数
bind(hello, "hello bind")();
cout << bind(sum, 10, 20)() << endl;
cout<<bind(&test::sum, test(), 20, 30)()<<endl;
//2.参数占位符 最多绑定20个参数
bind(hello, placeholders::_1)("hello bind2");
//using namespace placeholders; 有了这句话就可以不写前面的作用域,直接写_1,_2最多20个
cout<<bind(sum, _1, _2)(100, 200)<<endl;
//3.绑定器除了当前语句无法继续使用 解决方法:function
//此处把bind返回的绑定器就复用起来了
function<void(string)> func1 = bind(hello,_1);
func1("hello china");
func1("hello a");
func1("hello b");
return 0;
}
4.bind 和 function实现线程池
#include <iostream>
#include <functional>
#include <vector>
#include <thread>
using namespace std;
class Thread
{
public:
Thread(function<void()> func) : _func(func) {}
thread start() {
thread t(_func);
return t;
}
private:
function<void()> _func;
};
class ThreadPool
{
public:
ThreadPool() {}
~ThreadPool() {
//释放Thread对象占用的堆资源
for (int i = 0; i < _pool.size(); i++) {
delete _pool[i];
}
}
//开启线程池
void startPool(int size)
{
for (int i = 0; i < size; i++) {
//本身不可以是成员方法,但是可以用bind做到,i作为线程编号
_pool.push_back(new Thread(bind(&ThreadPool::runInThread, this, i)));
}
for (int i = 0; i < size; i++) {
_handler.push_back(_pool[i]->start());
}
for (thread& t : _handler) {
t.join();
}
}
private:
vector<Thread*> _pool;
vector<thread> _handler;
//把runInThread这个成员方法充当线程函数
void runInThread(int id) {
cout << "call runInThread id: " << id << endl;
}
};
int main()
{
ThreadPool pool;
pool.startPool(10);
return 0;
}
3.4 lambda表达式 底层依赖函数对象机制实现的
1.lambda概述
函数对象的的升级版----lambda
函数对象的缺点:
灵活性太差了,需要定一个类出来,但其实实际上我可能只需要在泛型算法里面用一次就不用了
2.lambda表达式的语法
语法:
[捕获外部变量](形参列表)->返回值{操作代码};
注意操作代码后面也有分号,句子结束也有分号,不要忘了,不要少写
如果没有返回值"->返回值"这部分可以省略
关于形参列表部分,如果参数,关键字,返回值一个都没有,那小括号可写可不写,如果有一个那就得写小括号
形参列表对应的是函数对象中operator()()的形参列表
lambda匿名函数中的[外部变量]
外部变量指的是和lambda在一个作用域的变量,写[=]把同一作用域和更外层的变量拷贝一个副本
这个应该对应函数对象的类里面的成员变量
外部变量格式 | 功能 |
---|---|
[] | 空方括号表示当前 lambda 匿名函数中不导入任何外部变量。 |
[=] | 只有一个 = 等号,表示以值传递的方式导入所有外部变量; |
[&] | 只有一个 & 符号,表示以引用传递的方式导入所有外部变量; |
[val1,val2,…] | 表示以值传递的方式导入 val1、val2 等指定的外部变量,同时多个变量之间没有先后次序; |
[&val1,&val2,…] | 表示以引用传递的方式导入 val1、val2等指定的外部变量,多个变量之间没有前后次序; |
[val,&val2,…] | 以上 2 种方式还可以混合使用,变量之间没有前后次序。 |
[=,&val1,…] | 表示除 val1 以引用传递的方式导入外,其它外部变量都以值传递的方式导入。 |
[this] | 表示以值传递的方式导入当前的 this 指针。 |
注意,单个外部变量不允许以相同的传递方式导入多次。例如 [=,val1] 中,val1 先后被以值传递的方式导入了 2 次,这是非法的。
代码示例:
#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
#include<ctime>
#include<typeinfo>
using namespace std;
using namespace placeholders;
template<typename T=void>
class testLambda01
{
public:
testLambda01(){}
void operator()()
{
cout << "hello world" << endl;
}
};
template<typename T = int>
class testLambda02
{
public:
testLambda02() {}
int operator()(int a,int b)
{
return a + b;
}
};
template<typename T = int>
class testLambda03
{
public:
testLambda03(int a,int b):ma(a),mb(b) {}
//常方法里面不能修改成员变量
//1.成员变量加mutable
//2.lambda加关键字mutable
void operator()() const
{
int tmp = ma;
ma = mb;
mb = tmp;
}
private:
mutable int ma;
mutable int mb;
};
int main()
{
int a = 10;
int b = 20;
auto func3 = [a, b]()mutable
{
int tmp = a;
a = b;
b = tmp;
};
func3();
cout << "a " << a << "b " << b << endl;
testLambda03<> t3(a, b);
t3();
cout << "a " << a << "b " << b << endl;
return 0;
}
template<typename T = int>
class testLambda04
{
public:
testLambda04(int &a, int &b):ma(a),mb(b) {}
//常方法里面不能修改成员变量
//1.成员变量加mutable
//2.lambda加关键字mutable
void operator()() const
{
int tmp = ma;
ma = mb;
mb = tmp;
}
private:
int &ma;
int &mb;
};
int main()
{
auto func1 = []()->void {cout << "hello world"<<endl; };
func1();
auto func2 = [](int a, int b)->int {return a + b; };
cout << func2(20, 30) << endl;
//func1的函数对象版本
testLambda01<> t1;
t1();
//func2的函数对象版本
testLambda02<> t2;
cout<<t2(20,30)<<endl;
//虽然实现了func3lambda对应的函数对象,但是a,b根本上还是没变(因为是值传递,不是引用),没有实现交换这个功能
int a = 10;
int b = 20;
auto func3 = [a, b]()mutable
{
int tmp = a;
a = b;
b = tmp;
};
func3();
cout <<"a "<< a <<"b "<< b << endl;
testLambda03<> t3(a,b);
t3();
cout << "a " << a << "b " << b << endl;
//实现交换功能,按照引用来传递参数,lambda后面的mutable也不用加了
//函数对象里面的mutable也不用加了 因为交换改变的是ma,mb的内存里面的东西
/*int a = 10;
int b = 20;
auto func4 = [&a, &b]()
{
int tmp = a;
a = b;
b = tmp;
};
func4();
cout << "a " << a << " b " << b << endl;
testLambda04<> t4(a, b);
t4();
cout << "a " << a << " b " << b << endl;*/
return 0;
}
Q:为什么在类中换成引用类型就不需要mtable来修饰成员变量了?
在C++中,当成员变量是引用类型时,即使在const
成员函数内部,我们也可以通过这些引用来修改它们所引用的外部对象的状态。这是因为const
成员函数中的const
关键字限制了成员变量本身的“可修改性”(如果成员变量不是引用或指针的话),但它并不限制通过成员变量(如果它们是引用或指针)所间接访问的对象的可修改性。
具体来说,当一个成员函数被声明为const
时,这意味着该成员函数不能修改其所属对象的任何非静态成员变量(除非这些变量被声明为mutable
)。然而,这一规则并不适用于引用类型的成员变量,因为引用本身并不是对象,它只是对象的一个别名。当我们说“不能修改成员变量”时,实际上是指不能改变成员变量所引用的对象(如果成员变量是对象的话)或成员变量所指向的地址(如果成员变量是指针的话)。但是,如果成员变量是引用,并且它引用了一个外部对象,那么我们完全可以通过这个引用来修改那个外部对象的状态。
换句话说,const
成员函数中的const
性仅仅保证了成员函数不会改变其所属对象的“身份”(即不会改变成员变量的值,如果成员变量是值类型的话),但并不保证不会改变成员变量所引用的外部对象的“状态”。
3.lambda的应用实践
1.泛型算法之中
就使用这一下,不用麻烦的写函数对象
//1.vector从大到小排序的lambda排序
vector<int> v;
sort(v.begin(),v.end(),[](int a,int b)->bool
{
return a>b;
})
//2.找到第一个比65小的数字的位置插入65到这里
auto it=find_id(v.begin(),v.end(),[](int a)->bool{return a<65;});
if(it!=v.end())
v.insert(it,65);
为什么a,b在()而不是[]里面?
在C++中,当你使用lambda表达式作为sort
函数的比较函数时,lambda表达式的参数(在这个例子中是a
和b
)是通过operator()
函数传入的,而不是通过捕获列表[]
传入的。这是因为捕获列表[]
用于指定哪些外部变量应该被捕获到lambda表达式的内部作用域中,而不是用于接收函数参数。
2.既然lambda只能用在语句中,如果想跨语句使用之前定义好的lambda表达式怎么办?有什么类型表达lambda?
解决方法:用函数对象function表示lambda的类型,lambda->函数对象
class Data
{
public:
Data(int val1=10,int val2=10):ma(val1),mb(val2){}
bool operator>(const Data &data) const { return ma > data.ma; }
bool operator<(const Data &data) const { return ma < data.ma; }
int ma;
int mb;
}
int main ()
{
//1.function存储类型
map<int, function<int(int, int)>> caculateMap;
caculateMap [1] = [] (int a, int b)->int {return a + b; };
caculateMap [2] = [] (int a, inth)>int {return a - b; };
caculateMap [3] = [] (int a, int b)->int {return a * b; };
caculateMap [4] = [] (int a, int b)->int {return a / b; };
cout << "选择:";
int choice;
cin >> choice;
cout << "10 + 15:" << caculateMap[choice] (10, 15) << endl;
int main ()
// 2.智能指针自定义删除器
unique_ptr<FILE,function<void (FILE *)>>
pti1 (fopen ("data.txt", "w"), [] (FILE *pf) {fclose(pf); });
//3.优先级队列 默认要进行比较,因为底层是大根堆 但是>和<运算符重载有点麻烦且灵活性很差,每次都要改动
priority_queue<Data> queue;
queue.push(Data(10,20));
queue.push(Data(15,15));
queue.push(Data(20,30));
//修改后,加入了比较函数,比较灵活
using PFUNC=function<bool(Data&,Data&)>;
priority_queue<Data,vector<Data>,PFUNC>
q([](Data &d1,Data &d2)->bool
{
return d1.ma>d2.ma;
}
);
q.push(Data(10,20));
q.push(Data(15,15));
q.push(Data(20,30));
return 0;
}