STL中的约束器相关总结

摘要: STL里有仿函数的概念,而在应用仿函数的时候,仿函数与仿函数之间的适配引出了约束器的概念。这一节主要叙述一下一元函数对象基类unary_function、二元函数对象基类binary_function,以及两个约束器binder1st与binder2nd,同时给出一个场景,分析实现原理。

1:template <class Argclass Resultstruct unary_function;
2:template <class Arg1class Arg2class Resultstruct binary_function;
3: template <class Operationclass binder1st;
4: template <class Operationclass binder2nd;
5: template <class Operationclass T>
     binder2nd<Operationbind2nd (const Operationopconst Tx);
6: template <class Operationclass T>
          binder1st<Operationbind1st (const Operationopconst Tx);

        unary_function是一元函数对象的基类,unary_function作为一个基类并没有实现operator(),仅仅含有两个数据成员,operator()是由子类根据具体情况实现的。binary_function则是二元函数对象的基类,同样没有实现operator().
[cpp]  view plain copy
  1. template <class Arg, class Result>   
  2. struct unary_function {   
  3.     typedef Arg argument_type;   
  4.     typedef Result result_type;   
  5. };   
  6. // unary_function example   
  7. #include <iostream>   
  8. #include <functional>   
  9. using namespace std;   
  10. struct IsOdd : public unary_function<int,bool> {   
  11.     bool operator() (int number) {return (number%2==1);}   
  12. };   
  13. int main () {   
  14.     IsOdd IsOdd_object;   
  15.     IsOdd::argument_type input;   
  16.     IsOdd::result_type result;   
  17.     cout << "Please enter a number: ";   
  18.     cin >> input;   
  19.     result = IsOdd_object (input);   
  20.     cout << "Number " << input << " is " << (result?"odd":"even") << ".\n";   
  21.     return 0;   
  22. }  

[cpp]  view plain copy
  1. template <class Arg1, class Arg2, class Result>   
  2. struct binary_function {   
  3.     typedef Arg1 first_argument_type;   
  4.     typedef Arg2 second_argument_type;   
  5.     typedef Result result_type;   
  6. };   
  7. // binary_function example   
  8. #include <iostream>   
  9. #include <functional>   
  10. using namespace std;   
  11. struct Compare : public binary_function<int,int,bool> {   
  12.     bool operator() (int a, int b) {return (a==b);}   
  13. };   
  14. int main () {   
  15.     Compare Compare_object;   
  16.     Compare::first_argument_type input1;   
  17.     Compare::second_argument_type input2;   
  18.     Compare::result_type result;   
  19.     cout << "Please enter first number: ";   
  20.     cin >> input1;   
  21.     cout << "Please enter second number: ";   
  22.     cin >> input2;   
  23.     result = Compare_object (input1,input2);   
  24.     cout << "Numbers " << input1 << " and " << input2;   
  25.     if (result)   
  26.         cout << " are equal.\n";   
  27.     else   
  28.         cout << " are not equal.\n";   
  29.     return 0;   
  30. }  

binder1st 与 binder2nd 的作用都是由二元函数对象得到一个一元函数对象,他们是"函数对象的适配器",其中binder1st 将第一个参数固定为一个固定的数值,binder2nd 将第二个参数固定为一个固定的数值。具体使用的时候,将某一个参数绑定为操作的第一个或者第二个参数,要根据操作语义而定,见如下示例。而bind2nd 与bind1st就是为了产生这两种对象而存在的。

[cpp]  view plain copy
  1. template <class Operation> class binder1st   
  2. public unary_function <typename Operation::second_argument_type,   
  3. typename Operation::result_type>   
  4. {   
  5. protected:   
  6.     Operation op;   
  7.     typename Operation::first_argument_type value;   
  8. public:   
  9.     binder1st ( const Operation& x,   
  10.         const typename Operation::first_argument_type& y) : op (x), value(y) {}   
  11.     typename Operation::result_type   
  12.         operator() (const typename Operation::second_argument_type& x) const   
  13.     { return op(value,x); }   
  14. };   
  15. // binder1st example   
  16. #include <iostream>   
  17. #include <functional>   
  18. #include <algorithm>   
  19. using namespace std;   
  20. int main () {   
  21.     binder1st < equal_to<int> > equal_to_10 (equal_to<int>(),10);  // 这里将10版定位(equal_to<int>())操作的第一个参数   
  22.     int numbers[] = {10,20,30,40,50,10};   
  23.     int cx;   
  24.     cx = count_if (numbers,numbers+6,equal_to_10);   
  25.     cout << "There are " << cx << " elements equal to 10.\n";   
  26.     return 0;   
  27. }  

[cpp]  view plain copy
  1. template <class Operation> class binder2nd   
  2. public unary_function <typename Operation::first_argument_type,   
  3. typename Operation::result_type>   
  4. {   
  5. protected:   
  6.     Operation op;   
  7.     typename Operation::second_argument_type value;   
  8. public:   
  9.     binder2nd ( const Operation& x,   
  10.         const typename Operation::second_argument_type& y) : op (x), value(y) {}   
  11.     typename Operation::result_type   
  12.         operator() (const typename Operation::first_argument_type& x) const   
  13.     { return op(x,value); }   
  14. };   
  15. // binder2nd example   
  16. #include <iostream>   
  17. #include <functional>   
  18. #include <algorithm>   
  19. using namespace std;   
  20. int main () {   
  21.     binder2nd < less<int> > IsNegative (less<int>(),0); // 这里将0绑定为(less<int>())操作的第二个参数   
  22.     int numbers[] = {10,-20,-30,40,-50};   
  23.     int cx;   
  24.     cx = count_if (numbers,numbers+5,IsNegative);   
  25.     cout << "There are " << cx << " negative elements.\n";   
  26.     return 0;   
  27. }  

下面给出一个场景分析:
现在定义一个函数对象如下inserter ,完成的功能是向vector中插入数据,如下可见在实际使用的时候传递两个参数。
[cpp]  view plain copy
  1. struct inserter {   
  2. public:   
  3.     void operator()(double n, vector<double> & v) { v.push_back(n); }   
  4. };   
  5. inserter f;   
  6. vector<double> vd;   
  7. f(1.0, vd); //两个参数  

如果现在有一个算法append是如下定义的,向容器中添加一些数据成员。
[cpp]  view plain copy
  1. template<typename Functor>   
  2. void append(Functor f) {   
  3.     double x;   
  4.     while(cin>>x)   
  5.         f(x);   
  6. }  

这时,你的insert就用不上了,因为append的functor只要求一个参数。如果你的inserter本来是一个很复杂的操作,那么如果重写一个就很麻烦。不过有一个简单的办法是再定义一个inserter_adapter。
[cpp]  view plain copy
  1. template<typename Functor>   
  2. struct inserter_adapter {   
  3.     inserter_adapter(const Functor& f, vector<double>& v)   
  4.         :f_(f), v_(v) {}   
  5.     void operator()(double x) { f_(x, v_);}   
  6.     Functor f_;   
  7.     vector<double>& v_;   
  8. };   
  9. inserter f;   
  10. vector<double> vd;   
  11. inserter_adapter ia(f, vd);  //将vd绑定到操作符f的第二个参数上   
  12. append(ia);  

      由以上的场景分析,可以看出inserter_adapter 充当了一个适配器的角色,解决了二元函数对象无法适应一元函数对象操作的情况。因为inserter_adapter 将容器参数对象绑定到了操作符的第二个参数上。
        以上方案实现的是将二元函数对象转化为一元函数对象,这种转化是通过绑定一个操作对象。而在STL中,这种参数绑定操作可以通过以上介绍的binder2nd或者binder1st实现。
[cpp]  view plain copy
  1. struct inserter :public std::binary_function<double, vector<double>&, void> {   
  2. public:   
  3.     void operator()(double n, vector<double> & v) { v.push_back(n); }   
  4. };   
  5. template<typename Functor>   
  6. void append(Functor f) {   
  7.     double x;   
  8.     while(cin>>x)   
  9.         f(x);   
  10. }   
  11. inserter f;   
  12. vector<double> vd;   
  13. append(std::bind2nd(f, vd)); //bind2nd创建了一个binder2nd对象,将参数vd绑定到操作符f的第二个参数  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值