- 通用泛型函数的谓词函数问题
- 方法一:普通函数当做实参
bool GT6(const string &s) //判断字符串长度是否大于6 { return s.size() >= 6; } vector<string>::size_type wc = count_if(word.begin(),word.end(), GT6)
由于count_if算法运行只用一个形参且返回bool的函数,所以对于判断的字符串长度6这个变量不能作为函数的参数,所以这样的函数就只能定义为死的判断多大长度的
- 方法二:使用函数对象
对于定义了调用操作符的类,起对象成为函数对象,即他们是行为类似函数的对象,如下
class GT_cls { public: GT_cls(size_t n = 0):length(n) {} bool operator()(const string &s) {retrun s.size() >= length;} private: std::string:size_type length; }; wc = count_if(word.begin(),word.end(), GT_cls(6));
可以更改上述中GT_cls(6)中的6的值,从而达到计算不同长度的目的。
- 方法三: 使用标准库函数对象和函数对象的函数适配器
标准库函数对象 定义在头文件 functional中,如下图
对于,sort函数,我们可以有
sort(word.begin(), word.end(), greater<string>()); //按降序对容器进行排序
标准库函数对象中,除了一元减和逻辑非之外,其他的都是两个操作数的二元函数对象。
而对于有的泛型函数的谓词函数,其需要一个操作数的一元函数对象
此时,可以使用函数对象的函数适配器,函数适配器分为两种,
1)绑定器(binder):通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象。bind1st,将给定值绑定到二元函数对象的第一个实参,bind2nd将给定值绑定到二元函数的第二个实参.
2)求反器:它将谓词对象的真值求反。其中not1将一元函数的真值求反,not2将二元函数的真值求反。
如:
count_if(vec.begin(), vec.end(), bind2nd(greater_equal<int>(), 6)); //判断值是否大于等于6 count_if(vec.begin(), vec.end(), not1(bind2nd(greater_equal<int>(), 6))); //判断值小于6 count_if(vec.begin(), vec.end(), bind2nd(less<int>(), 6)); //判断值小于6
当然在这里,不能使用count_if和函数对象结合来解决这个问题,这是由于count_if的谓词函数的左操作数是string,而绑定的第二个参数是 int,无法比较。
我们可以不使用 count_if,可以直接使用 if(greater_equal(str.size(), 6))来判断,然后做相关的操作.
- 方法四: lamda表达式
count_if(words.begin(),words.end(),[sz](const string &s){return s.size()>=sz})
sz为使用前已经赋值的变量
- 方法五:使用C++11新标准 bind函数
bind函数是C++11标准新定义的通用的函数适配器
bool check_size(const string &s,string::size_type sz) { return s.size()>=sz; } auto check6 = bind(check_size, _1, 6); count_if(words.begin(), words.end(), bind(check_size, _1, 6));
check6(s),相当于调用check_size(s,6);
bind(check_size, _1, 6)
_n表示的是生成的可调用对象(这里是check6)中参数的位置, _1是生成的可调用对象的第一个参数,_2是第二个参数;_n就是占位符
其中_n(这里是_1)定义在额名为placeholders的命名空间中,而这个命名空间定义在std命名空间中,所以在使用_1之前,应当有适当的using声明
using std::placeholders::_1
当然为了简化,不用写所有需要的_n,可以
using namespace std::placeholders