Bogotobogo
contact@bogotobogo.com
- C++ Home
- String
- Constructor
- Operator Overloading
- Virtual Functions
- Dynamic Cast Operator
- Type Cast Operators
- Class auto_ptr
- References for Built-in Types
- Pass by Value vs. Pass by Reference
- Memory Allocation
- Friend Functions and Friend Classes
- Functors (Function Objects)
- Static Variables and Static Class Members
- Exceptions
- Stack Unwinding
- Pointers
- Pointers II - void pointers & arrays
- Pointers III - pointer to function & multi-dimensional arrays
- Taste of Assembly
- Small Programs
- Linked List Examples
- Binary Tree Example Code
- Templates
- Standard Template Library (STL) I
- Standard Template Library (STL) II - Maps
- Standard Template Library (STL) III - Iterators
- Standard Template Library (STL) IV - Algorithms
- Object Slicing and Virtual Table
- The this Pointer
- Stack Unwinding
- Upcasting and Downcasting
- Object Returning
- Private Inheritance
- Preprocessor - Macro
- C++_Keywords
- fstream: input & output
- Multi-Threaded Programming - Terminology
- Multi-Threaded Programming II - Native Thread for Win32 (A)
- Multi-Threaded Programming II - Native Thread for Win32 (B)
- Multi-Threaded Programming II - Native Thread for Win32 (C)
- Multi-Threaded Programming II - C++ Thread for Win32
- Multi-Threaded Programming III - C++ Class Thread for Pthreads
- Multithread Debugging
- Socket - Server & Client
- Embedded Systems Programming
- Boost
- make
- Debugging Crash & Memory Leak
- Libraries
- C++ API Testing
- Design Patterns in C++
- Algorithms in C++
- Programming Questions and Solutions
- Blackjack with Qt
Functors (Function Objects or Functionals) are simply put object + (). In other words, a functor is any object that can be used with () in the manner of a function.
This includes normal functions, pointers to functions, and class objects for which the () operator (function call operator) is overloaded, i.e., classes for which the function operator()() is defined.
Sometimes we can use a function object when an ordinary function won't work. The STL often uses function objects and provides several function objects that are very helpful.
Function objects are another example of the power of generic programming and the concept of pure abstraction. We could say that anything that behaves like a function is a function. So, if we define an object that behaves as a function, it can be used as a function.
For example, we could defin a struct names absValue that encapsulates the operation of converting a value of type float to its absolute valie:
#include <iostream>
struct absValue
{
float operator()(float f) {
return f > 0 ? f : -f;
}
};
int main( )
{
using namespace std;
float f = -123.45;
absValue aObj;
float abs_f = aObj(f);
cout << "f = " << f << " abs_f = " << abs_f << endl;
return 0;
}
Output is:
f = -123.45 abs_f = 123.45
As we see from the definition, even though aObj is an object and not a function, we were able to make a call on that object. The effect is to run the overloaded call operator defined by the object absValue. Tha operator takes a float value and returns its absolute value. Note that the function-call operator must be declared as a member function.
So, Objects of class types, like the absValue object, that define the call operator are referred to as function object.
Let's look at another example simulating a line. The class object is working as a functor taking x for a given y-intercept(b) and slope(a) giving us the corresponding y coordinate.
y = ax + b
Here is the code:
#include <iostream>
using namespace std;
class Line {
double a; // slope
double b; // y-intercept
public:
Line(double slope = 1, double yintercept = 1):
a(slope),b(yintercept){}
double operator()(double x){
return a*x + b;
}
};
int main () {
Line fa; // y = 1*x + 1
Line fb(5.0,10.0); // y = 5*x + 10
double y1 = fa(20.0); // y1 = 20 + 1
double y2 = fb(3.0); // y2 = 5*3 + 10
cout << "y1 = " << y1 << " y2 = " << y2 << endl;
return 0;
}
Here y1 is calculated using the expression 1 * 20 + 1 and y2 is calculated using the expression 5 * 3 + 10. In the expression a *x + b, the values for b and a come from the constructor for the object, and the value of x comes from the argument to operator()().
Now that we have a little bit of taste for functor, let's step back and think. So, what's the behavior of a function? A functional behavior is something that we can call by using parentheses and passing arguments. For example:
func(arg1, arg2);
If we want objects to behave this way, we have to make it possible to call them by using parentheses and passing arguments. It's not that difficult. All we have to do is to define operator () with the appropriate parameter types:
Class X {
public:
// define "function call" operator
return-value operator() (arguments) const;
...
};
Then we can use object of this class to behave as a function that we can call:
X fn; ... fn(arg1, arg2); // call operator () for function object fn
This call is equivalent to:
fn.operator()(arg1,arg2); // call operator () for function object fn
Here is a function object example.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Print {
public:
void operator()(int elem) const {
cout << elem << " ";
}
};
int main () {
vector vect;
for (int i=1; i<10; ++i) {
vect.push_back(i);
}
Print print_it;
for_each (vect.begin(), vect.end(), print_it);
cout << endl;
return 0;
}
The for_each function applied a specific function to each member of a range:
for_each (vect.begin(), vect.end(), print_it);
In general, the 3rd argument could be a functor, not just a regular function. Actually, this raises a question. How do we declare the third argument? We can't declare it as a function pointer because a function pointer specifies the argument type. Because a container can contain just about any type, we don't know in advance what particular type should be used. The STL solves that problem by using template.
The class Print defines object for which we can call operator () with an int argument. The expression
print_itin the statement
for_each (vect.begin(), vect.end(), print_it);creates a temporary object of this class, which is passed to the for_each() algorithm as an argument. The for_each algorithm looks like this:
template<class Iterator, class Function>
Function for_each(Iterator first, Iterator last, Function f) {
while (first != end) {
f(*first);
++first;
}
return f;
}
for_each uses the temporary function f to call f(*first) for each element first. If the third parameter is an ordinary function, it simply call it with *first as an argument. If the third parameter is a function object, it calls operator() for the function object f with *first as an argument. Thus, in this example for_each() calls:print_it::operator()(*first)The out is:
1 2 3 4 5 6 7 8 9
Here are some advantages of function object listed in "The C++ Standard Library" by Nicolai M. Josuttis.
- Function object are "smart functions."
Objects that behave like pointers are smart pointers. This is similarly true for objects that behave like functions: They can be "smart functions" because they may have abilities beyond operator (). Function objects may have other member functions and attributes. This means that function objects have a state. .... - Each function object has its own type.
Ordinary functions have different types only when their signatures differ. However, function objects can have different types when their signatures are the same. In fact, each functional behavior defined by a function object has its own type. This is a significant improvement for generic programming using templates because you can pass functional behavior as a template parameter. ... - Function objects are usually faster than ordinary functions.
The concept of templates usually allows better optimization because more details are defined at compile time. Thus, passing function objects instead of ordinary functions often results in better performance.
STL refines functor concepts as follows:
- A generator is a functor that can be called with no argument.
- A unary function is a functor that can be called with one argument.
- A binary function is a functor that can be called with two arguments.
The print_it functor for for_each() we used in the previous section is a unary function because it is applied to one container element at a time.
A special auxiliary function for algorithm is a predicate. Predicates are functions that return a Boolean value (or something that can be implicitly converted to bool). In other words, a predicate class is a functor class whose operator() function is a predicate, i.e., its operator() returns true or false.
Predicates are widely used in the STL. The comparison functions for the standard associative containers are predicates, and predicate functions are commonly passed as parameters to algorithms like find_if. Depending on their purpose, predicates are unary or binary.
- A unary function that returns a bool value is a predicate.
- A binary function that returns a bool value is a binary predicate.
- C++ Home
- String
- Constructor
- Operator Overloading
- Virtual Functions
- Dynamic Cast Operator
- Type Cast Operators
- Class auto_ptr
- References for Built-in Types
- Pass by Value vs. Pass by Reference
- Memory Allocation
- Friend Functions and Friend Classes
- Functors (Function Objects)
- Static Variables and Static Class Members
- Exceptions
- Stack Unwinding
- Pointers
- Pointers II - void pointers & arrays
- Pointers III - pointer to function & multi-dimensional arrays
- Taste of Assembly
- Small Programs
- Linked List Examples
- Binary Tree Example Code
- Templates
- Standard Template Library (STL) I
- Standard Template Library (STL) II - Maps
- Standard Template Library (STL) III - Iterators
- Standard Template Library (STL) IV - Algorithms
- Object Slicing and Virtual Table
- The this Pointer
- Stack Unwinding
- Upcasting and Downcasting
- Object Returning
- Private Inheritance
- Preprocessor - Macro
- C++_Keywords
- fstream: input & output
- Multi-Threaded Programming - Terminology
- Multi-Threaded Programming II - Native Thread for Win32 (A)
- Multi-Threaded Programming II - Native Thread for Win32 (B)
- Multi-Threaded Programming II - Native Thread for Win32 (C)
- Multi-Threaded Programming II - C++ Thread for Win32
- Multi-Threaded Programming III - C++ Class Thread for Pthreads
- Multithread Debugging
- Socket - Server & Client
- Embedded Systems Programming
- Boost
- make
- Debugging Crash & Memory Leak
- Libraries
- C++ API Testing
- Design Patterns in C++
- Algorithms in C++
- Programming Questions and Solutions
- Blackjack with Qt