• STL源码剖析(仿函数/bind2nd)


    仿函数(functors)其实就是重载了operator()的对象。

    下面简单先看看它的一个例子:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 template<typename T>
     5 struct m_plus
     6 {
     7     T operator()(const T& x, const T& y) { return x + y; }
     8 };
     9 
    10 int main(int argc, char *argv[])
    11 {
    12     // 定义其对象  调用其operator()
    13     m_plus<int> op;
    14     cout << op(1, 2) << endl;
    15     // 产生一个匿名对象  这是仿函数的主流用法
    16     cout << m_plus<int>()(1, 2) << endl;
    17     return 0;
    18 }
    View Code

    既然仿函数跟函数的用法类同,那为什么不直接使用函数指针代替呢?

    个人认为有两个原因

    1.仿函数可以有自己的状态,而函数指针则不行(有的使用template或者static变量可以实现)。

    我们可以这样子使用仿函数:

     1 #include <iostream>
     2 using namespace std;
     3 
     4 template<typename T, T add>
     5 struct m_plus
     6 {
     7     m_plus() { _add = add; }
     8     T operator()(const T& x) { return x + _add; }
     9     // 仿函数可以具有自己的状态
    10     int _add;
    11 };
    12 
    13 int main(int argc, char *argv[])
    14 {
    15     m_plus<int, 10> op;
    16     cout << op(100) << endl;
    17     cout << op(200) << endl;
    18     return 0;
    19 }
    View Code

    2.仿函数可以与函数适配器搭配使用。

    举一个例子,例如我们如果要使用count_if算法来计算容器中大于10的元素的个数。

    如果我们使用greater<int>作为判别式(二元),而count_if只接受一个一元判别式,这时候我们就需要搭配函数适配器一起使用了。

    而函数指针不能直接搭配函数适配器一起使用,具体在分析bind2nd的时候会讲到。

     1 #include <iostream>
     2 #include <vector>
     3 #include <functional>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 
     8 int main(int argc, char *argv[])
     9 {
    10     vector<int> coll{ 1, 3, 5, 7, 9, 11, 13, 15 };
    11     // 接着下面有bind2nd的具体实现
    12     cout << count_if(coll.begin(), coll.end(), bind2nd(greater<int>(), 10)) << endl;
    13     return 0;
    14 }
    View Code

    bind2nd

    bind2nd可以将二元仿函数转化为一元仿函数,这看上去好像很神奇,其实它的实现很简单。

    首先,二元仿函数会继承自binary_function,其实只是一些typedef,这些都将用于函数适配器。

     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 
     8 template <class T>
     9 struct greater : public binary_function<T, T, bool> {
    10     bool operator()(const T& x, const T& y) const { return x > y; }
    11 };
    View Code

    bind2nd将二元仿函数跟第二个参数型别作为模板型别,下面是具体实现:

     1 template <class Operation, class T>
     2 inline binder2nd<Operation> bind2nd(const Operation& op, const T& x) {
     3     typedef typename Operation::second_argument_type arg2_type;
     4     // 调用binder2nd
     5     return binder2nd<Operation>(op, arg2_type(x));
     6 }
     7 
     8 // binder2nd是一个一元仿函数(本身可以搭配函数适配器一起使用)
     9 template <class Operation> 
    10 class binder2nd
    11   : public unary_function<typename Operation::first_argument_type,
    12                           typename Operation::result_type> 
    13 {
    14 protected:
    15     // 传进来的二元仿函数
    16     Operation op;
    17     // 传进来的第二个参数  因为仿函数内部可以typedef  而函数指针则不行
    18     // 因此只能适配仿函数  而不能适配函数指针
    19     typename Operation::second_argument_type value;
    20 public:
    21     // 构造函数
    22     binder2nd(const Operation& x,
    23             const typename Operation::second_argument_type& y) 
    24        : op(x), value(y) {}
    25 
    26     // 直接调用二元仿函数 
    27     typename Operation::result_type
    28     operator()(const typename Operation::first_argument_type& x) const {
    29         return op(x, value); 
    30     }
    31 };
    View Code
  • 相关阅读:
    elemntui-tab添加图标
    动态添加input,然后获取所有的input框中的值
    jmeter_使用接口传递数据
    python_异常
    python_内置函数和open
    jmeter_安装
    jmeter_使用_设置代理录制脚本
    python_函数
    python_while
    python_if、for
  • 原文地址:https://www.cnblogs.com/runnyu/p/6010101.html
Copyright © 2020-2023  润新知