STL基础--仿函数(函数对象)

Posted logchen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL基础--仿函数(函数对象)相关的知识,希望对你有一定的参考价值。

1 首先看个仿函数的例子

class X {
   public:
   void operator()(string str) {     // 函数调用运算符,返回类型在operator之前
      cout << "Calling functor X with parameter " << str<< endl;
   }  
    operator string () const { return "X"; } //类型转换函数,返回类型在operator之后
};

int main()
{
   X foo;
   foo("Hi");    // 以参数HI调用仿函数X
}
/*
 * 仿函数的好处:
 * 1. 智能函数: 比常规函数有更多的功能,比如可以保存状态(参数化的函数)
 * 2. 有它自己的类型,不用考虑函数重名问题
 * 事实上,类带来的其他好处,封装,继承,多态都可以是仿函数的好处
 */

2 参数化的函数

class X {
   public:
   X(int i) {}
   void operator()(string str) { 
      cout << "Calling functor X with parameter " << str<< endl;
   }
};

int main()
{
   X(8)("Hi");
}

// 为什么需要参数化函数,用2个参数的函数代替不行么?


// 只实现+2的功能,如果我想实现加任何数的功能
void add2(int i) {
   cout << i+2 << endl;
}

// 用全局变量,显然不好
// 用模板实现,加任何值的功能,但是val需要编译时常数
template<int val>
void addVal(int i) {
   cout << val+i << endl;
}

// 轮到仿函数登场了
class AddValue {
   int val;
   public:
   AddValue(int j) : val(j) { }
   void operator()(int i) {
      cout << i+val << endl;
   }
};

int main()
{
   vector<int> vec = { 2, 3, 4, 5};   
   //for_each(vec.begin(), vec.end(), add2); // {4, 5, 6, 7}
   int x = 2;
   //for_each(vec.begin(), vec.end(), addVal<x>); // {4, 5, 6, 7} ,编译不过
   for_each(vec.begin(), vec.end(), AddValue(x)); // {4, 5, 6, 7}
}

3 内置的仿函数

// 比较 less greater  greater_equal  less_equal  not_equal_to
// 逻辑 logical_and  logical_not  logical_or
// 算术 multiplies minus  plus  divide  modulus  negate

int x = multiplies<int>()(3,4);  //  x = 3 * 4 

if (not_equal_to<int>()(x, 10))   // if (x != 10)
   cout << x << endl;

4 参数绑定

set<int> myset = { 2, 3, 4, 5};   
vector<int> vec;


int x = multiplies<int>()(3,4);  //  x = 3 * 4 

// 将元素值乘以10,保存在vec中:
transform(myset.begin(), myset.end(),    // 源
          back_inserter(vec),              // 目的
            bind(multiplies<int>(), placeholders::_1, 10));  // 仿函数
    // multiplies<int>()的第1个参数替换为myset中的元素值
    // vec: {20, 30, 40, 50}


void addVal(int i, int val) {
   cout << i+val << endl;
}
for_each(vec.begin(), vec.end(), bind(addVal, placeholders::_1, 2));

// C++ 03: bind1st, bind2nd

5 将常规函数转为仿函数

double Pow(double x, double y) {
    return pow(x, y);
}

int main()
{
  set<int> myset = {3, 1, 25, 7, 12};
  deque<int> d;
  auto f = function<double (double,double)>(Pow);   //C++ 11
  transform(myset.begin(), myset.end(),     // 源地址
              back_inserter(d),              // 目的
                bind(f, placeholders::_1, 2));  // 仿函数
            //  d: {1, 9, 49, 144, 625}
}
// C++ 03中使用ptr_fun 

6 lambda函数

// 想拷贝5<x<20之间的元素到d
set<int> myset = {3, 1, 25, 7, 12};
deque<int> d;

// 定义一个函数
bool needCopy(int x){
   return (x>20)||(x<5);
}
// 或者用内置仿函数和bind结合
// 两种方法都不方便

transform(myset.begin(), myset.end(),     // source
          back_inserter(d),               // destination
          needCopy
          );

/*
          bind(logical_or<bool>, 
              bind(greater<int>(), placeholders::_1, 20),
              bind(less<int>(), placeholders::_1, 5))
*/

// C++ 11 lambda function:
transform(myset.begin(), myset.end(),     // source
          back_inserter(d),              // destination
          [](int x){return (x>20)||(x<5);}    //lambda函数
          );

7 为什么STL中需要仿函数?

set<int> myset = {3, 1, 25, 7, 12}; // myset: {1, 3, 7, 12, 25}
// 同:
set<int, less<int> > myset = {3, 1, 25, 7, 12};

bool lsb_less(int x, int y) {
      return (x%10)<(y%10);
}

class Lsb_less {
   public:
   bool operator()(int x, int y) {
      return (x%10)<(y%10);
   }
};
int main()
{
  set<int, Lsb_less> myset = {3, 1, 25, 7, 12};  // myset: {1,12,3,25,7}
  ...
}

8 谓词

 /*
 * 一种特殊的仿函数:
 * 1. 返回一个boolean值
 * 2. 不改变数据
 */

class NeedCopy {
   bool operator()(int x){   
      return (x>20)||(x<5);  
   }
};

transform(myset.begin(), myset.end(),     // source
          back_inserter(d),               // destination
          NeedCopy()
          );

// 谓词用于比较或者条件判断

以上是关于STL基础--仿函数(函数对象)的主要内容,如果未能解决你的问题,请参考以下文章

C++入门基础教程:STL函数对象

STL 仿函数(函数对象)

STL简单函数对象(仿函数)的实现

SGI STL functors(仿函数) 12

[C++STL]仿函数用法介绍

STL——容器(Set & multiset)之 仿函数(函数对象)functor 的用法