文章目录
一.引言
在c++中,谓词就是可以做谓语的词,就是“动词、动作”性质语义的词。c/c++中的函数func就是典型的谓词语义。c++中STL中的谓词类似这样:bool func(T&a);或者bool func(T&a,T&b);
常见的谓词:函数、函数指针、函数对象、lambda表达式,库定义的函数对象。
如find_if(),count_if()等函数需要传入bool型的判断条件参数,因此会经常用到谓词,下面以count_if()函数为例简要介绍以上几种谓词的实现方法。
二.实现及源码
1.使用函数做谓词
#include<iostream>
#include<vector>
#include<functional> //bind2nd函数需使用
#include<algorithm>
using namespace std;
//定义函数,作为传入参数
bool bigthan3(int val)
{
return val > 3;
}
//计算容器vec中大于3的元素个数
int main(void)
{
vector<int> vec={1,2,3,4,5,6};
int CountNum = count_if(vec.begin(),vec.end(),bigthan3); //传入的是bigthan3谓词,返回的是bool类型,其中自动将vec容器中的元素值传给bigthan3函数
cout<<"CountNum = "<<CountNum <<endl;
return 0;
}
//输出结果:CountNum = 3;
2.使用函数指针做谓词,与上述函数做谓词基本一致,只是使用函数指针中转了一次。
#include<iostream>
#include<vector>
#include<functional> //bind2nd函数需使用
#include<algorithm>
using namespace std;
//定义函数,作为传入参数
bool bigthan3(int val)
{
return val > 3;
}
//计算容器vec中大于3的元素个数
int main(void)
{
bool (*p_bigthan3)(int); //定义函数指针
p_bigthan3 = bigthan3;
vector<int> vec={1,2,3,4,5,6};
int CountNum = count_if(vec.begin(),vec.end(),p_bigthan3); //传入的是p_bigthan3函数指针做谓词,返回的是bool类型,其中自动将vec容器中的元素值传给bigthan3函数
cout<<"CountNum = "<<CountNum <<endl;
return 0;
}
//输出结果:CountNum = 3;
3.使用函数对象做谓词(一元仿函数,比较参数固定)
函数对象使用的本质就是对()进行运算符重载,并且返回类型为bool型。
#include<iostream>
#include<vector>
#include<functional> //bind2nd函数需使用
#include<algorithm>
using namespace std;
//定义仿函数类
class bigthan3
{
public:
bool operator()(int val)const //对()实现重载,注意一定要加const修饰
{
return val > 3;
}
};
//计算容器vec中大于3的元素个数
int main(void)
{
vector<int> vec={1,2,3,4,5,6};
int CountNum = count_if(vec.begin(),vec.end(),bigthan3()); //传入的是bigthan3仿函数,返回的是bool类型,其中自动将vec容器中的元素值传给bigthan3函数
cout<<"CountNum = "<<CountNum <<endl;
return 0;
}
//输出结果:CountNum = 3;
另外对于函数对象的使用还可以将比较参数作为函数对象的构造函数传递给()运算符重载函数,具体使用如下:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class myfind
{
public:
//默认构造函数
myfind() {}
//有参构造函数
myfind(int my_n):n(my_n)
{
}
bool operator()(int val)
{
return val > n;
}
private:
int n;
};
int main(void)
{
vector<int>vec1 = { 1,2,4,9,5,54,45,56 };
auto iter = find_if(vec1.begin(), vec1.end(), myfind(1)); //使用函数对象做谓词,并且入口参数作为谓词判断的条件
for_each(iter, vec1.end(), [](int val) {cout << val << " "; });
cout << endl;
}
其中myfind(1)是调用了函数对象,1是传递给myfind对象的构造函数,而并不是()运算符重载函数,而使用find_if泛型算法遍历vec1容器的元素是传递给()运算符重载函数的。一定要区分清楚!因此myfind(1)在这里实际完成了两件事情:一是调用myfind的构造函数,二是将()运算符重载函数作为谓词传给find_if泛型算法。
4.使用lambda表达式做判断条件参数
#include<iostream>
#include<vector>
#include<functional> //bind2nd函数需使用
#include<algorithm>
using namespace std;
//计算容器vec中大于3的元素个数
int main(void)
{
vector<int> vec={1,2,3,4,5,6};
int CountNum = count_if(vec.begin(),vec.end(),[](int val){return val>3;}); //传入的是lambda表达式,返回的是bool类型,其中val为遍历vec容器传入的元素值
cout<<"CountNum = "<<CountNum <<endl;
return 0;
}
//输出结果:CountNum = 3;
5.使用仿函数加bind2nd实现二元参数的传入,比较参数不固定。
观察上面4种方式可以看出比较的条件都是大于3,3这个参数只能固定,因为上述的方式只能传入一个参数,那就是vec自身的元素。如果想要实现比较参数自定义,那就需要给bool比较函数传入两个参数,因此可以使用仿函数结合bind2nd函数的方式实现。
#include<iostream>
#include<vector>
#include<functional> //bind2nd函数需使用
#include<algorithm>
using namespace std;
//定义仿函数类
class bigthan3:public binary_function<int, int, bool> //必须继承binary_function类,<参数1,参数2,返回值>
{
public:
bool operator()(int val1,int val2)const //对()实现重载,注意一定要加const修饰
{
return val1 > val2;
}
};
//计算容器vec中大于4的元素个数
int main(void)
{
vector<int> vec={1,2,3,4,5,6};
int a = 4; //比较值可以自定义
int CountNum = count_if(vec.begin(),vec.end(),bing2nd(bigthan3(),a)); //传入的是bigthan3仿函数,并且通过bind2nd函数给bigthan3添加了一个参数a,这样比较的入口参数就包含vec本身元素及a共两个,返回的是bool类型
cout<<"CountNum = "<<CountNum <<endl;
return 0;
}
//输出结果:CountNum = 2;
/*
bind2nd绑定的使用步骤:
1.包含bind2nd头文件:#include<functional>
2.在find_if中进行绑定:bind2nd(mycompare,p1)
3.在mycompare类中进行绑定登记:
首先继承public binary_function<person,person,bool>,其中<>中的参数代表第一个参数,第二个参数,返回值
然后定义operator()函数为const类型
*/
三.总结
以上几个示例展示了谓词的几种常用实现方法,对于find_if等其他类似的函数都可以使用这种方式。另vector中的元素可以泛化成为类,不局限与特定的数据类型,只需要在重载函数中明确其比较方式即可。