初接触仿函数

在学习到《Essential C++》3.6节时自己按照自己的想法来实现书上提到的思路。代码虽然简单,不过自己却发现有很多其他地方不熟悉,比如函数指针的用法,仿函数和函数适配器的使用。捣鼓了半天,总算懂了点眉目,简单总结下以备忘。

文档按照五部分分写,先依次简单地介绍find()与find_if()算法、提及函数作为参数的用法(我犯错了,这里。)、仿函数(functon object)和函数适配器(function adapters)。最后贴上自己实验的代码并简单分析指出错误。

一、
因为问题起于泛型搜索算法find_if(),所以先总结下有关find()和find_if()。

Code:
  1. 声明:   
  2.  InputIterator   
  3.  find (InputIterator beg, InputIterator end, const T& value)   
  4.   
  5.  InputIterator   
  6.  find_if(InputIterator beg, InputIterator end, UnaryPredicate op)   

第一种形式返回在搜索域[beg,end)内与value值相等的元素的地址;
第二种形式返回在搜索域[beg,end)内满足一元谓词函数op(elem)为真的元素的地址。
? 1)以上两种形式在搜索不到匹配元素的情况下均返回end;
? 2)注意op函数调用期间不能够改变自身的状态;
? 3)op不能更改传递进来的参数;

二、
为了增强泛型算法的灵活性,一些泛型算法允许传递用户自定的的函数。泛型算法在使用辅助函数时有不同的方式,有些是可以省略的,即算法是可以不用给定的函数,而有些是
强制性的,即必须使用这些函数。如下 

Code:
  1. // CODE SNIPPET   
  2.  void print (int elem)   
  3.  {     
  4.   cout <<elem <<’ ‘;   
  5.  }   
  6.  ……   
  7.  for_each (coll.begin(), coll.end(), print);   

注意如上for_each语句中的第三个参数,这个参数接受一个函数指针,此时传递的便是函数print()的地址(和数组类似,其名也可指示其地址)。注意,此时不要用print(elem).

一种特殊的辅助函数便是谓词函数,谓词函数通常指的是返回值为boolean的函数,它们通常用来为排序或者搜索算法指定参照条件。在使用中谓词函数可分为带有一个参数的谓词函数(unary)和需要两个参数的谓词函数(binary),值得注意的是并不是所有返回值为boolean类型的函数都是合法的谓词函数。

三、
仿函数是一种对象,但它具有函数一样的功能,并且比函数更有优势。其中一点便是效率更高。我们使用的仿函数通常被声明为inline,所以其大部分执行逻辑在编译时已经基本
确定,因而少掉了频繁调用函数的开销。

可以自己定义简单的仿函数,如下:

Code:
  1. // CODE SNIPPET   
  2. class Print{   
  3.  public:   
  4.   void operator() (int elem) const  
  5.   {   
  6.    cout <<elem <<’ ‘;   
  7.    }   
  8. };   
  9. ……   
  10. for_each (coll.begin(), coll.end(), Print());   
  11. ……  

C++的STL中提供了多种预定义的仿函数,如negate<type>(), plus<type>(), minus<type>(), multiplies<type>(), divides<type>(), modulus<type>(), equal_to<type>(),not_equal_to<type>(), less<type>(), greater<type>(), less_equal<type>(), greater_equal<type>(), logical_not<type>(), logical_and<type>(), logical_or<type>().

四、
函数适配器也是一种仿函数,不过这种仿函数更为高等,因为它可以将一个仿函数与另一个仿函数/ 值/ 特殊的函数结合起来。

不难发现,STL常使用仿函数虽然提供了多种有用的仿函数,然而这些仿函数均是通过迭代器对容器里面的元素进行操作,但是有时候你还需要用其他的值结合,这时候便可以使用函数适配器(见下面的例子)。

编译不能通过的代码如下所示:
 

Code:
  1. // code snippet   
  2. #include <iostream>   
  3. #include <vector>   
  4. #include <algorithm>   
  5. #include <functional>   
  6.   
  7. using namespace std;   
  8.   
  9. bool less_than(int a, int b)   
  10. {   
  11.  return (a<b ? true:false);   
  12. }   
  13.   
  14. vector<int> filter(const vector<int> &vec, int filter_value, bool (*ptr_func)(intint))   
  15. {   
  16.  vector<int> temp;   
  17.  vector<int>::const_iterator iter = vec.begin();   
  18.   
  19.  while (find_if(iter, vec.end(), ptr_func(*iter, filter_value)) != vec.end())   
  20.  {   
  21.   temp.push_back(*iter);   
  22.   ++iter;   
  23.  }    
  24.  return temp;   
  25. }   
  26.   
  27. void display(vector<int> &vec)   
  28. {   
  29.  for (int ix=0; ix<vec.size(); ++ix)   
  30.   cout <<vec[ix] <<" ";   
  31.  cout <<"/n";   
  32. }   
  33.     
  34. int main()   
  35. {   
  36.  const int nsize = 5;   
  37.  int int_arr[nsize] = { 2, 4, 5, 6, 7};   
  38.  vector<int>vec(int_arr, int_arr+nsize);   
  39.  display(vec);   
  40.  vector<int>result;   
  41.   
  42.  result = filter(vec, 6, less_than);   
  43.  display(result);   
  44.     
  45.  return 0;    
  46. }  

可见,我在使用find_if()函数的时候,将里面本应该为“函数指针”的第三个参数写成了对这个函数的“函数调用”,这是不允许的。但整个程序的思路并没有错,因为上面的代码可以通过仿函数来解决的。

上面也提到,一般通用的仿函数仅是对容器里面的值进行处理,但本例的思路是需要将容器里面的每个值以此与另一个值val进行比较的。所以必须要使用到函数适配器来将一个仿函数与一个值进行绑定。如下是更正后的代码:

Code:
  1. // code snippet   
  2. #include <iostream>   
  3. #include <vector>   
  4. #include <algorithm>   
  5. #include <functional>   
  6.   
  7. using namespace std;   
  8.   
  9. bool less_than(int a, int b)   
  10. {   
  11.  return (a<b ? true:false);   
  12. }   
  13.   
  14. vector<int> filter(const vector<int> &vec, int val, less<int><)   
  15. {   
  16.  vector<int> nvec;   
  17.  vector<int>::const_iterator iter = vec.begin();   
  18.     
  19.  while ((iter=find_if(iter, vec.end(), bind2nd(lt, val))) != vec.end())   
  20.  {   
  21.   nvec.push_back(*iter);   
  22.   iter ++;   
  23.  }   
  24.  return nvec;   
  25. }   
  26.   
  27. void display(vector<int> &vec)   
  28. {   
  29.  for (int ix=0; ix<vec.size(); ++ix)   
  30.   cout <<vec[ix] <<" ";   
  31.  cout <<"/n";   
  32. }   
  33.     
  34. int main()   
  35. {   
  36.  const int nsize = 5;   
  37.  int int_arr[nsize] = { 2, 4, 5, 6, 7};   
  38.  vector<int>vec(int_arr, int_arr+nsize);   
  39.  display(vec);   
  40.  vector<int>result;   
  41.   
  42.  result = filter(vec, 6, less<int>());   
  43.  display(result);   
  44.     
  45.  return 0;    
  46. }   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值