3.C++11中引入的bind绑定器和function函数对象
绑定器bind1st,bind2nd
vector<int> vec;
for(int i=0;i<20;i++){
vec.push_back(rand()%100);
}
showContainer(vec);
sort(vec.begin(),vec.end(),greater<int>());
showContainer(vec);
/*
* greater a>b
* less a<b
* */
//把70按顺序插入到vector容器中
auto it= find_if(vec.begin(), vec.end(), bind1st(greater<int>(),70));//两种绑定器的用法
//auto it= find_if(vec.begin(), vec.end(), bind2nd(less<int>(),70));
if(it!=vec.end()){
vec.insert(it,70);
}
showContainer(vec);
绑定器的实现原理
绑定器其实是函数对象的一个应用!!绑定器+二元函数对象+值=一元函数对象。底层还是靠二元函数对象做事
自己实现一个绑定器:
/**
*
* @tparam Compare 函数对象类型
* @tparam T 对象类型
*/
template<typename Compare,typename T>
class CMyBind1st{
public:
CMyBind1st(Compare com,T val):_comp(com),_val(val){}
/**
* 绑定器函数对象的实现,实际上是传入的函数对象在干活
* @param second 传入要绑定的数据
* @return 函数对象,这个函数对象干完传回的数据
*/
bool operator()(const T &second){
return _comp(_val,second);
}
private:
Compare _comp;
T _val;
};
/**
* 实现绑定器
* @tparam Compare 返回函数对象类型
* @tparam T 数据对象
* @param comp 函数对象
* @param val 绑定数据
* @return
*/
template<typename Compare,typename T>
CMyBind1st<Compare,T> my_bind1st(Compare comp,const T &val){
return CMyBind1st<Compare,T>(comp,val);
}
/**
*
* @tparam Compare 函数对象类型
* @tparam T 对象类型
*/
template<typename Compare,typename T>
class CMyBind2nd{
public:
CMyBind2nd(Compare com,T val):_comp(com),_val(val){}
/**
* 绑定器函数对象的实现,实际上是传入的函数对象在干活
* @param second 传入要绑定的数据
* @return 函数对象,这个函数对象干完传回的数据
*/
bool operator()(const T &first){
return _comp(first,_val);
}
private:
Compare _comp;
T _val;
};
/**
* 实现绑定器
* @tparam Compare 返回函数对象类型
* @tparam T 数据对象
* @param comp 函数对象
* @param val 绑定数据
* @return 返回的是一个函数对象
*/
template<typename Compare,typename T>
CMyBind2nd<Compare,T> my_bind2nd(Compare comp,const T &val){
return CMyBind2nd<Compare,T>(comp,val);
}
/////////////////
/**
* 实现find_if
* @tparam Iterator 迭代器
* @tparam Compare 函数对象
* @param begin
* @param end
* @param comp 函数对象
* @return 迭代器
*/
template<typename Iterator,typename Compare>
Iterator my_find_if(Iterator begin,Iterator end,Compare comp){
for(;begin!=end;++begin){
if(comp(*begin)){//comp.operator()(*begin)
return begin;
}
}
return end;
}
function函数对象的应用
首先讲一下什么是函数指针:
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
那么这个指针变量怎么定义呢?虽然同样是指向一个地址,但指向函数的指针变量同我们之前讲的指向变量的指针变量的定义方式是不同的。例如:
int(*p)(int, int);
这个语句就定义了一个指向函数的指针变量 p。首先它是一个指针变量,所以要有一个“”,即(p);其次前面的 int 表示这个指针变量可以指向返回值类型为 int 型的函数;后面括号中的两个 int 表示这个指针变量可以指向有两个参数且都是 int 型的函数。所以合起来这个语句的意思就是:定义了一个指针变量 p,该指针变量可以指向返回值类型为 int 型,且有两个整型参数的函数。p 的类型为 int(*)(int,int)。
所以函数指针的定义方式为:函数返回值类型 (* 指针变量名) (函数参数列表);
函数指针的使用:
int Func(int x); /*声明一个函数*/
int (*p) (int x); /*定义一个函数指针*/
p = Func; /*将Func函数的首地址赋给指针变量p*/
# include <stdio.h>
int Max(int, int); //函数声明
int main(void)
{
int(*p)(int, int); //定义一个函数指针
int a, b, c;
p = Max; //把函数Max赋给指针变量p, 使p指向Max函数
printf("please enter a and b:");
scanf("%d%d", &a, &b);
c = (*p)(a, b); //通过函数指针调用Max函数
printf("a = %d\nb = %d\nmax = %d\n", a, b, c);
return 0;
}
int Max(int x, int y) //定义Max函数
{
int z;
if (x > y)
{
z = x;
}
else
{
z = y;
}
return z;
}
输出结果是:
please enter a and b:3 4
a = 3
b = 4
max = 4
function:
void hello1(){
cout<<"hello1"<<endl;
}
void hello2(string str){
cout<<str<<endl;
}
int sum(int a,int b){
return a+b;
}
class TT{
public:
TT()=default;
void hello(string str) const {
cout<<"call TT::hello"<<str<<endl;
}
};
int main(){
function<void()> func1=hello1;
function<void(string)> func2=hello2;
func1();
func2("sashkgf");
function<int(int,int)> func3=sum;
cout<<func3(20,22)<<endl;
function<void(TT*,string)> func4=&TT::hello;
TT t;
func4(&t,"asgasgxb");
return 0;
}
使用function需要注意两点:
- 用函数类型实例化function
- 通过function调用operator()函数的时候,需要根据函数类型传入相应的参数
一个function应用的例子:
void doShow(){cout<<"查看所有书籍"<<endl;}
void doBorrow(){cout<<"借书"<<endl;}
void doBack(){cout<<"还书"<<endl;}
void doQuery(){cout<<"查询书籍"<<endl;}
void doLogout(){cout<<"注销"<<endl;}
int main(){
int choice=0;
map<int,function<void()>> actionMap;
actionMap.insert({1,doShow});
actionMap.insert({2,doBorrow});
actionMap.insert({3,doBack});
actionMap.insert({4,doQuery});
actionMap.insert({5,doLogout});
for(;;){
cout<<"————————————————————"<<endl;
cout<<"1_查看所有书籍"<<endl;
cout<<"2_借书"<<endl;
cout<<"3_还书"<<endl;
cout<<"4_查询书籍"<<endl;
cout<<"5_注销"<<endl;
cout<<"————————————————————"<<endl;
cin>>choice;
auto it= actionMap.find(choice);
if(it==actionMap.end()){
cout<<"输入数字无效,请重新选择"<<endl;
}else{
it->second();
}
}
return 0;
}
输出:
1_查看所有书籍
2_借书
3_还书
4_查询书籍
5_注销
4
查询书籍
如何实现function
首先介绍两个前置知识:
模板的完全特例化和非完全特例化
模板的实参推演
实现function
template<typename Fty>//必须要有
class MyFunction{};
template<typename R,typename... A>//非完全特例化
class MyFunction<R(A...)>{//function其实就是函数指针的封装
public:
using PFUNC=R(*)(A...);//函数指针
MyFunction(PFUNC pfunc):_pfunc(pfunc){}
R operator()(A... arg){
return _pfunc(arg...);
}
private:
PFUNC _pfunc;
};
int main(){
MyFunction<void(string)> func2=hello2;
func2("sashkgf");
MyFunction<int(int,int)> function= sum;
cout<<function(20,30)<<endl;
return 0;
}
使用bind和function实现线程池
C++11里的绑定器bind返回的还是是一个函数对象
//TODO 学完线程再回来写这个笔记
lambda表达式
lambda表达式的语法:[捕获外部变量](形参列表)->返回值{操作代码}
如果lambda表达式的返回值不需要,那么->返回值
可以省略
[捕获外部变量]
lambda表达式生成的函数对象的()重载默认是const常量形的,不能对内部的值进行修改,需要在lambda表达式的后面加mutable标识符才可以修改(只有是传值的情况下需要加这个标识符)。如果是[&]的情况就不需要加这个标识符
使用lambda表达式实现优先级队列:
class Data{
public:
Data(int val1=10,int val2=10):ma(val1),mb(val2){}
int ma;
int mb;
};
int main(){
using FUNC=function<bool(Data&,Data&)>;
priority_queue<Data,vector<Data>,FUNC> que([](Data& d1,Data& d2)->bool{//在构造函数中使用lambda表达式传入函数对象
return d1.ma>d2.ma;
});
que.push({10,20});
que.push({20,10});
que.push({30,40});
return 0;
}