Functor lists provide a mechanism for grouping together a number of different functions into one coherent object. With a single invocation, several related tasks can be accomplished.
Because this single invocation shares its API with the basic functors, functor lists can be used wherever a functor is expected but a sequence of functors would be more useful. In fact, the code to which the functor list is passed need not know. The code invokes what appears to be a simple functor, and the list handles the complexity of invoking all of its encapsulated functions.
For example, suppose a button widget invokes a functor when pushed. If your application needs to associate a number of actions with the button, you can group them together in a functor list and pass that list to the button widget. When the button is pushed, the widget invokes the functor list, and all of the actions are fired. The button widget code doesn't change at all.
Like basic functors, functor lists are implemented by a number of template classes. Depending on the number of arguments passed at invocation time, different functor lists are required.
Because the invocation of the list invokes all the functors within the list, they all must have the same invocation signature and either share the same functor handle type or be derived from the same functor handle type.
Like functors, functor lists use the handle body idiom. Because each functor list handle can point to exactly one type of functor list, however, the body is created automatically as a part of the handle's construction. Copying functor lists follows the general rules discussed in Section 7.3.1.4, "Handle-body Mechanics." With this technique, the copy constructor and assignment operators reference the old object and, as a result, are very fast.
NOTE: After the assignment, changes to either functor list object affect the other one.
The Functor List subpackage is made up of classes designed to accommodate functor arguments of different numbers and types. Functor list classes are an extension to the functor class hierarchy, as shown in Figure 51.
Class names are constructed from the base name RWTFunctorList for templatized classes or RWFunctorList for the few non-templatized classes by adding 0, 1 or 2 for the number of caller arguments.
The formal template parameters (shown in the hierarchy) include:
S1 - The type of the functor list's first argument.
S2 - The type of the functor list's second argument.
NOTE: Functor lists do not provide R0, R1, or R2 classes.
The specific type of functor list that you need depends on the type of functors to be held within the list. All functors in a list must be of the same handle type or be derived from the same handle type. If you are starting with a function that you wish to wrap, see Section 8.4.1, "Analyzing Functor Requirements," to select a functor type.
To construct a functor list, you need to know what type of list to create, based on the functor type.
The following steps show how to create a functor list to hold a set of functors.
Start with a set of functions, for example:
void foo(int int_arg) { cout << "foo was passed " << int_arg << endl; } void bar(short short_arg){ cout << "bar was passed " << short_arg << endl;}
Decide what functor type you need and build functors from the functions:
RWTFunctor1<short> fooFunctor = rwtMakeFunctor1( (void(*)(short))NULL, foo); RWTFunctor1<short> barFunctor = rwtMakeFunctor1( (void(*)(short))NULL, bar);
Create the appropriate functor list to hold that functor type:
RWTFunctorList1<short> flist;
At this point, you have a complete but empty functor list instance. Next, you add functors to the list, as shown in Example 74.
When adding a functor, you can specify how long it remains a part of the list. If the functor will remain indefinitely, add it with the RW_CALL_REPEATEDLY flag. If you intend to call the functor only once, however, add it with the RW_CALL_ONCE flag.
NOTE: Functors added with the RW_CALL_ONCE flag are automatically removed after invocation.
// foo_functor will be removed after one // functor list invocation. flist.add(fooFunctor, RW_CALL_ONCE); // bar_functor will remain in the list until // explicitly removed. flist.add(barFunctor, RW_CALL_REPEATEDLY);
Once the list contains entries, you can invoke it. Invocation consists of iterating through the list invoking each functor with the given caller values and then removing the functor from the list, if it was added with the RW_CALL_ONCE flag.
NOTE: If you invoke a functor list that has no entries, nothing happens.
For example, suppose you call the functor list with the functors added in the previous section, like this:
flist(3);
This call performs the following actions:
Calls fooFunctor, passing it the value 3
Removes fooFunctor from the list, due to the RW_CALL_ONCE flag
Calls barFunctor with the value 3, but does not remove it from the list, because of the RW_CALL_REPEATEDLY flag
This output is produced:
foo was passed 3 bar was passed 3
If you invoked the list a second time, only barFunctor would be invoked, because fooFunctor was removed.
To remove a functor from the list, call the remove() function with the functor to be removed.
flist.remove(barFunctor);
To provide the maximum level of concurrency, additions and removals are buffered, and the actual update of the list is postponed until the next list invocation. The performance hit for updating a list is small in most cases. If an extremely large number of additions and or removals are done, however, this cost can become non-trivial. For such cases, the functor list classes have an update() function, which forces an update immediately.
flist.update();
Use of this function is not required and will not change the program's logic.
Example 75 shows how to use a functor list as a callback. It is essentially the same as the pushButton example in examples\thr0200osfam\functor, except that replacing a functor with a functor list enables you to attach more than one callback to the button. This complete example is available in examples\thr0200osfam\functor\list\pushButtonList.cpp.
#include <rw/functor/list/list.h> // include all functor list // headers #include <rw/functor/functor0.h> // include all functor0 headers ... // A simplistic button widget class pushButton { public: pushButton(RWFunctorList0 functor0list): _functorlist(functor0list) {} void push(void) { _functorlist(); } private: // Since the pushButton class will not have any useful // information to pass to the functor invocation, // we choose to use an RWFunctor0 RWFunctor0 _functorlist; }; // Functions that we might like to attach to the button RWBoolean action(RWCString string, int& counter, int max) { cout << string << ++counter << endl; return (counter > max) ? TRUE: FALSE; } void action2(RWCString string) { cout << string << endl; } int main() { // Create a functor for each function attached to the button RWFunctor0 pushButton_functor= rwtMakeFunctor0GA3 (RWBoolean, action, RWCString, message, int&, counter, int, 0); RWFunctor0 pushButton_functor2= rwtMakeFunctor0GA1(void, action2, RWCString, message2); // Create a functorList RWFunctorList0 functorList; // Add functors to the list functorList.add(pushButton_functor, RW_CALL_REPEATEDLY); functorList.add(pushButton_functor2, RW_CALL_REPEATEDLY); // Create a push button with our functorList pushButton our Push Button( functorList ); // Calls both action() and action2() ourPushButton.push(); return 0; }
©Copyright 2000, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.