How-to: Overload the C++ function operator()
r3dux | January 20, 2012I’m working my way through the first few chapters of James Reinders’ Intel Threading Building Blocks book, and its a little bit hard going. As much as I’m enjoying the mental exercise of thinking in parallel, when it actually comes to the coding they use a lot of function operator (i.e. operator()) overloading, and I’m not so familiar with it. As much as I’ve overloaded operators before so you could, for example, add two Fruit objects together and get their weight, or multiply an Employee->monthlySalary by 12 to get their yearly wage, I’d never overloaded the function operator itself, so wasn’t sure what was really going on in the code.
To fix this, I’ve knocked together a super-simple example to show how it works:
#include <iostream> using std::cout; using std::endl; class Foo { public: // Property int number; // Constructor Foo() : number(0) { cout << "Constructing an object of type Foo..." << endl; } // First overloaded function operator, i.e. we're overloading the operator () void operator()() { cout << "From our first overloaded () operator, I get the number: " << number << endl; } // Second overloaded function operator void operator()(Foo &first, Foo &second) { if (first.number > second.number) { cout << "The first number property is greater than the second number property." << endl; } else { cout << "The first number property is less than or equal to the second number property." << endl; } } }; void doNothing(Foo tempFoo) { cout << "I'm not using the overloaded () operator here." << endl; } int main() { // Create our first test object Foo firstObject; // Make sure it's initialised with the default value specified in the constructor cout << "From main, number is: " << firstObject.number << endl; // Call the doNothing function on our Foo object - doesn't do a lot! doNothing(firstObject); // Anonymous object creation (i.e. invokes the constructor - but we don't keep a named object) Foo(); // ***THIS*** is where the overloaded function operator comes in! firstObject(); // Create a second test object and specify a value Foo secondObject; secondObject.number = 5; // Run our first overloaded function operator again on a different object secondObject(); // Run our second overloaded function operator on the first object firstObject(firstObject, secondObject); // Run our second overloaded () operator (function operator) again, but on diff object // It doesn't matter which object we run it on - behviour is only dependant on the order // in which we supply the object parameters in this case! secondObject(firstObject, secondObject); // Finally, just to prove we can trigger the second path in the 2nd overloaded function operator... secondObject(secondObject, firstObject); return 0; } |
Which gives the output:
Constructing an object of type Foo... From main, number is: 0 I'm not using the overloaded () operator here. Constructing an object of type Foo... From overloaded () operator, I got the number: 0 Constructing an object of type Foo... From overloaded () operator, I got the number: 5 The first number property is less than or equal to the second number property. The first number property is less than or equal to the second number property. The first number property is greater than the second number property.
So, that’s how it works. Straight forward enough.
Another example, taken from the Function object wikipedia page:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <iostream> #include <iterator> #include <algorithm> class countfrom { private: int &count; public: countfrom(int &n) : count(n) {} int operator()() { return count++; } }; int main() { int state(10); std::generate_n(std::ostream_iterator<int>(std::cout, "\n"), 11, countfrom(state)); return 0; } |
Counting from 10 to 20 has never been funner =D









