C++仿函数

定义

functor的英文解释为something that performs a function,即其行为类似函数的东西。C++中的仿函数是通过在类中重载()运算符实现,使你可以像使用函数一样来创建类的对象。

C中是怎么实现这个功能的

使用指针函数和回调函数,比如qsort的比较函数

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
int sort_function( const void *a, const void *b) {
return *(int*)a-*(int*)b;
}
int main() {
int list[5] = { 54, 21, 11, 67, 22 };
qsort((void *)list, 5, sizeof(list[0]), sort_function); //起始地址,个数,元素大小,回调函数
int x;
for (x = 0; x < 5; x++)
printf("%i\n", list[x]);
return 0;
}

C++ 中的仿函数

  • 一个例子(增加任意常数)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // this is a functor
    struct add_x {
    add_x(int x) : x(x) {}
    int operator()(int y) { return x + y; }
    private:
    int x;
    };
    // usage:
    add_x add42(42); // create an instance of the functor class
    int i = add42(8); // and "call" it
    assert(i == 50); // and it added 42 to its argument
    std::vector<int> in(10);
    std::vector<int> out(10);
    for (size_t i = 0; i < in.size(); ++i) {
    in[i] = i;
    }
    // Pass a functor to std::transform, which calls the functor on every element
    // in the input sequence, and stores the result to the output sequence
    std::transform(in.begin(), in.end(), out.begin(), add_x(1));
    for (size_t i = 0; i < in.size(); ++i) {
    assert(out[i] == in[i] + 1);
    }
  • 迭代和计算逻辑分开(for_each 求和例子)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     struct sum {
    sum(int* t):total(t){};
    int* total;
    void operator()(int element) {
    *total += element;
    }
    };
    int main() {
    int total = 0;
    sum s(&total);
    int arr[] = {0, 1, 2, 3, 4, 5};
    std::for_each(arr, arr + 6, s);
    cout << total << endl; // prints total = 15;
    }

    for_each 为STL的非变易算法,是一组不破坏操作数据的模板函数,对[first,last)数据逐个处理,执行由单参数函数对象所定义的操作。

  • 仿函数可以是有状态的,可以应用到多个集合中。
    一个例子(对多个数据集取平均)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class CalculateAverage {
    public:
    CalculateAverage() : acc(0), n(0) {}
    void operator() (float x) { acc += x; n++; }
    float getAverage() const { return acc / n; }
    private:
    float acc;
    int n;
    };
    CalculateAverage avg;
    avg = std::for_each(dataA.begin(), dataA.end(), avg);
    avg = std::for_each(dataB.begin(), dataB.end(), avg);
    avg = std::for_each(dataC.begin(), dataC.end(), avg);
    cout << avg.getAverage() << endl;
  • 仿函数的性能
    使用仿函数编译器可以准确知道需要调用哪个函数。这意味着它可以内联这个函数调用。而如果使用函数指针,编译器不能直接确定指针指向的函数,而这必须在程序运行时才能得到并调用。一个例子就是比较std::sort 和qsort ,STL的版本一般要快5-10倍。
  • STL 内建仿函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    plus<T>
    // plus example
    #include <iostream> // std::cout
    #include <functional> // std::plus
    #include <algorithm> // std::transform
    int main () {
    int first[]={1,2,3,4,5};
    int second[]={10,20,30,40,50};
    int results[5];
    std::transform (first, first+5, second, results, std::plus<int>());
    for (int i=0; i<5; i++)
    std::cout << results[i] << ' ';
    std::cout << '\n';
    return 0;
    }
    // 输出
    // 11 22 33 44 55
    minus<T>
    multiplies<T>
    divides<T>
    modulus<T>
    negate<T>
    equal_to<T>
    // equal_to example
    #include <iostream> // std::cout
    #include <utility> // std::pair
    #include <functional> // std::equal_to
    #include <algorithm> // std::mismatch
    int main () {
    std::pair<int*,int*> ptiter;
    int foo[]={10,20,30,40,50};
    int bar[]={10,20,40,80,160};
    ptiter = std::mismatch (foo, foo+5, bar, std::equal_to<int>());
    std::cout << "First mismatching pair is: " << *ptiter.first;
    std::cout << " and " << *ptiter.second << '\n';
    return 0;
    }
    // 输出
    // First mismatching pair is: 30 and 40
    not_equal_to<T>
    greater<T>
    greater_equal<T>
    less<T>
    less_equal<T>
    logical_and<T>
    // logical_and example
    #include <iostream> // std::cout, std::boolalpha
    #include <functional> // std::logical_and
    #include <algorithm> // std::transform
    int main () {
    bool foo[] = {true,false,true,false};
    bool bar[] = {true,true,false,false};
    bool result[4];
    std::transform (foo, foo+4, bar, result, std::logical_and<bool>());
    std::cout << std::boolalpha << "Logical AND:\n";
    for (int i=0; i<4; i++)
    std::cout << foo[i] << " AND " << bar[i] << " = " << result[i] << "\n";
    return 0;
    }
    // 输出
    // Logical AND:
    // true AND true = true
    // false AND true = false
    // true AND false = false
    // false AND false = false
    logical_or<T>
    logical_no<T>
打赏
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

小小鼓励一下~

支付宝
微信