Introduction Function object is any object for which the function call operator is defined, i.e., operator()
is overloaded. It is also called functor.
Suppose we want to implement a function which requires a lot of parameters and the parameters would be set during runtime, using functors would be convenient because the parameters could be saved in the functor instance when it is created. This also means we can create a family of the functions using different parameters easily. In addition, by using C++ runtime polymorphism, i.e., function overriding, we could defer the functor type determination to runtime.
In this blog post, I would like to show some of the functor implementations.
Examples The following example presents a couple of functors which use default and non-default parameters, how to pass functor to functions using pointer, and how to integrate functors with template.
functors.cpp 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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 #include <iostream> #include <vector> #include <algorithm> class CircleArea { public : CircleArea () { } CircleArea (double pi) : mPi{pi} { } double operator () (double r) const { return this ->mPi * r * r; } private : double mPi{3.1415926 }; }; template <class T >class UnaryFunction { public : virtual T operator () (T x) const = 0 ; }; template <class T >class Increase : public UnaryFunction<T>{ public : Increase (T val) : mVal{val} { } T operator () (T x) const override { return x + this ->mVal; } private : T mVal; }; template <class T >class Decrease : public UnaryFunction<T>{ public : Decrease (T val) : mVal{val} { } T operator () (T x) const override { return x - this ->mVal; } private : T mVal; }; template <class T >class BinaryFunction { public : virtual T operator () (T x, T y) const = 0 ; }; template <class T >class Add : public BinaryFunction<T>{ public : T operator () (T x, T y) const override { return x + y; } }; template <class T >class Minus : public BinaryFunction<T>{ public : T operator () (T x, T y) const override { return x - y; } }; template <class T >T runBinaryFunction (T x, T y, BinaryFunction<T>* func) { return (*func)(x, y); } template <class T , class BinaryFunc >class Foo { public : T runBinaryFunction (T x, T y) { return this ->func (x, y); } private : BinaryFunc func; }; int main () { CircleArea computeCircleArea; CircleArea computeCustomCircleArea{3.14 }; double r{1.0 }; std::cout << computeCircleArea (r) << std::endl; std::cout << computeCustomCircleArea (r) << std::endl; Add<double > addDouble; Minus<double > minusDouble; double x{1.1 }; double y{2.2 }; std::cout << addDouble (x, y) << std::endl; std::cout << minusDouble (x, y) << std::endl; std::cout << runBinaryFunction (x, y, &addDouble) << std::endl; std::cout << runBinaryFunction (x, y, &minusDouble) << std::endl; std::vector<int > vec{1 ,2 ,3 ,4 ,5 }; std::vector<int > vecIncreaseOne; std::vector<int > vecIncreaseTen; Increase<int > increaseOne{1 }; Increase<int > increaseTen{10 }; std::transform (vec.begin (), vec.end (), std::back_inserter (vecIncreaseOne), increaseOne); std::transform (vec.begin (), vec.end (), std::back_inserter (vecIncreaseTen), increaseTen); for (int val : vecIncreaseOne) { std::cout << val << " " ; } std::cout << std::endl; for (int val : vecIncreaseTen) { std::cout << val << " " ; } std::cout << std::endl; Foo<int , Add<double >> fooAdd; std::cout << fooAdd.runBinaryFunction (1 , 2 ) << std::endl; Foo<int , Minus<double >> fooMinus; std::cout << fooMinus.runBinaryFunction (1 , 2 ) << std::endl; }
To compile the program, please run the following command in the terminal.
1 $ g++ functors.cpp -o functors -std=c++11
Conclusions Functors are less confusing and much easier to use compared to function pointers.