橙色
绑定器和函数对象operator()
函数对象就是对象拥有()运算符重载函数,这个对象使用起来就跟函数调用特别相似。
1.C++ STL中的绑定器
bind1st:operator ()的第一个形参变量绑定成一个确定的值
bind2nd:operator ()的第二个形参变量绑定成一个确定的值
2.C++11从Boost库中引入了bind绑定器和function函数对象机制
3.lambda表达式,底层依赖函数对象的机制实现的
bind1st和bind2nd这两个函数在functional库中。这两个函数都是用在二元函数对象身上的
注意代码第36行,find_if的第三个参数是需要一个一元的函数对象,因为它需要一次从容器中取出一个元素与70进行比较。因此没法直接使用algorithm库里的greater()等函数对象,因为它们都是二元的。
所以就引入了bind1st和bind2nd
绑定器+二元函数对象=一元函数对象
下面的例子中,通过find_if找到了小于70的第一个数,并把70插在了它的前面。greater()函数对象的逻辑是a>b,通过bind1st(greater(), 70)其函数对象的逻辑就变成了70>b,依此来寻找小于70的第一个元素。
同样也可以用less()来实现寻找小于70的第一个数的功能,因为该函数对象的逻辑是a
#include
这段代码是很精妙的,下面有详细的解释,可以好好看看
#include
#include
#include
#include
#include
using namespace std;
template<typename Container>
void showContainer(Container &con)
{
typename Container::iterator it = con.begin();
for (; it != con.end();it++)
{
cout << *it << " ";
}
cout << endl;
}
template<typename Iterator,typename Compare>
Iterator my_find_if(Iterator first,Iterator last,Compare comp)
{
for (; first != last;++first){
if(comp(*first))//comp.operator()(*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);
}
int main(){
vector<int> vec;
srand(time(nullptr));
for (int i = 0; i < 20;i++){
vec.push_back(rand()% 100 + 1);
}
//greater 二元函数对象
sort(vec.begin(), vec.end(), greater<int>());
showContainer(vec);
/*
把70按顺序插入到vec容器当中 找第一个小于70的数字
*/
auto it1 = my_find_if(vec.begin(), vec.end(), mybind1st(greater<int>(), 70));
cout << *it1 << endl;
if (it1 != vec.end()) {
vec.insert(it1, 70);
}
showContainer(vec);
return 0;
}
上面这段代码是对bind绑定器函数的一个实现。我的目标是在已经按降序排列的容器中把70按顺序插入到容器中,其实也就是找到小于70的第一个数字。my_find_if函数的形参有三个,分别是初始的迭代器,末尾的迭代器和一个二元函数对象。这个二元函数对象形参实际上传入的参数是mybind1st(greater(), 70),也就是传入的是mybind1st函数的返回值。
mybind1st函数返回的是一个二元函数对象_mybind1st
所以呢,my_find_if中的第3个形参cmp在本代码中实际上就是_mybind1st
bool operator()(const T&second)
{
return _comp(_val, second);
}
也就是挨个把_val(为70)和迭代器所指向的元素一起传入到_comp函数对象(也就是greater())中,看70是否大于该迭代器所指向的元素,是的话就返回该迭代器(也就是寻找到小于70的第一个元素,代码中容器初始顺序是从大到小)。
使用functioal函数对象类型需要头文件< functional >.
下面是几个简单的应用:
#include
#include
#include
using namespace std;
/*
function :绑定器,函数对象,lambda表达式它们只能使用在一条语句中
*/
void hello1()
{
cout << "hello world!" << endl;
}
void hello2(string str)
{
cout << str << endl;
}
int sum(int a,int b)
{
return a + b;
}
int main()
{
//从function的类模板定义处,看到希望用一个函数类型实例化function
function<void()> func1 = hello1;
func1(); //func1.operator()()=>hello1()
function<void(string)> func2 = hello2;
func2("hello hello2"); //func2.operator()(string str)=>hello2(str)
function<int(int, int)> func3 = sum;
cout << func3(20, 30)<<endl;
function<int(int,int)>func4=[](int a,int b)->int {return a+b;};
cout << func4(20, 30) << endl;
return 0;
}
上面这些例子都是通过function函数对象指向函数的,但function函数对象不仅可以指向函数,也可以指向类中的成员函数,但就没办法直接指向了,而是必须依赖于一个对象,参考下面的代码:
#include
#include
#include
using namespace std;
class Test
{
public://必须依赖一个对象
void hello(string str) { cout << str << endl; }
};
int main()
{
//因为类对象自带一个this指针,所以参数是两个
function<void(Test *, string)> func5 = &Test::hello;
Test a;
func5(&a, "call Test::hello!");
return 0;
}
看完上面这些内容,那function到底强大在哪里呢?直接用函数不也可以吗?看下面这个例子:
#include
#include
#include
using namespace std;
void doShowAllBooks() { cout << "查看所有书籍信息" << endl; }
void doBorrow() { cout << "借书" << endl; }
void doBack() { cout << "还书" << endl; }
void doQueryBooks() { cout << "查询书籍" << endl; }
void doLoginOut() { cout << "注销" << endl; }
int main()
{
int choice = 0;
map<int, function<void()>> actionMap;
actionMap.insert({1, doShowAllBooks});
actionMap.insert({2, doBorrow});
actionMap.insert({3, doBack});
actionMap.insert({4, doQueryBooks});
actionMap.insert({5, doLoginOut});
for (;;)
{
cout << "---------------------" << endl;
cout << "1、查看所有书籍信息" << endl;
cout << "2、借书" << endl;
cout << "3、还书" << endl;
cout << "4、查询书籍" << endl;
cout << "5、注销" << endl;
cout << "---------------------" << endl;
cout << "请选择:";
cin >> choice;
auto it=actionMap.find(choice);
if(it==actionMap.end()){
cout << "输入数字无效,重新选择" << endl;
}
else
{
it->second();
}
}
return 0;
}
假如直接在主函数中通过switch来实现也可以,但就不符合写代码的开闭原则;而且后面想加减功能就必须在主函数中改动。但像我们这么写,清晰明了,无论后续对功能作何种改动,都可以直接在相应函数上该,而不需要对主函数进行大的改动。
#include
#include
#include
#include
using namespace std;
int main()
{
vector<int> vec = {9, 7, 4, 2};
//寻找第一个小于5的数字,并按照降序插入其中
auto it = find_if(vec.begin(), vec.end(), [=](int a) -> bool
{ return a < 5; });
if(it!=vec.end()){
vec.insert(it, 5);
}
for(int val:vec){
cout << val << " ";
}
cout <<endl;
//找vec中的偶数并输出
for_each(vec.begin(), vec.end(), [](int a)
{
if(a%2==0)
cout << a << " ";
});
cout << endl;
return 0;
}
既然 lambda 表达式只能使用在语句当中,如果想跨语句使用之前定义好的lambda表达式,怎么办?用什么类型来表示lambda表达式?
当然是用function类型来表示函数对象的类型了
下面是一个函数对象方面应用的例子
#include
#include
#include
#include
#include
using namespace std;
//lambda表达式=》函数对象
int main()
{
map<int, function<int(int, int)>> caculateMap;
caculateMap[1]=[](int a,int b)->int{return a+b;};
caculateMap[2]=[](int a,int b)->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;
return 0;
return 0;
}
再举一个智能指针自定义删除器方面的例子:
#include
#include
#include
#include
#include
using namespace std;
int main()
{
unique_ptr<FILE, function<void(FILE *)>> ptr1(fopen("data.txt", "w"),
[](FILE *pf){ fclose(pf); });
return 0;
}
再举一个优先队列的例子:
下面的代码是会报错误的,因为优先队列默认的情况下维护的是一个大堆,即权值以从高到低排列。但此时传入的是一个自定义变量Data,所以就不知道该怎么排了
#include
#include
#include
#include
using namespace std;
class Data
{
public:
Data(int val1=10,int val2=10):ma(val1),mb(val2){}
int ma;
int mb;
};
int main()
{
priority_queue<Data> queue;
queue.push(Data(10, 20));
queue.push(Data(15, 15));
queue.push(Data(20, 10));
return 0;
}
我们可以通过lambda匿名函数这么写:
#include
#include
#include
#include
using namespace std;
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>
maxHeap([](Data &d1, Data &d2) -> bool
{
return d1.ma > d2.ma;
});
maxHeap.push(Data(10, 20));
maxHeap.push(Data(15, 15));
maxHeap.push(Data(20, 10));
return 0;
}