Threads Module User's Guide : PART III Foundation Packages : Chapter 8 The Functor Package : Binding Functor Arguments
Binding Functor Arguments
The Functor package supports creation of binder objects via the rwBind() function. Combined with RWTFunctor, this binder functionality can provide a powerful tool when adapting an existing function to match a common interface. For example, if a caller has specified a functor interface of RWTFunctor<void()>, but the function you would like to invoke takes a parameter, rwBind() can be used to specify the function argument when the functor is created instead of when it is invoked:
 
void function1(int);
RWTFunctor<void()> functor1 = rwBind(function1, 5);
When functor1 is invoked, function1 will be called with the bound argument 5.
rwBind() has the following signature:
 
rwBind(<callable>, <arg type 1>, <arg type 2>, …, <arg type N>)
Where <callable> is the callable object that will be invoked and <arg type 1>, <arg type 2>, …, <arg type N> are the arguments that <callable> will be invoked with. rwBind()returns a binder object, which is itself a function object that wraps <callable>, along with copies of the specified arguments. When the binder object is invoked, it will invoke <callable> with the arguments stored in the binder object.
Binding Reference Types
Callable objects that take parameters by-reference can be problematic when those arguments are bound. rwBind() creates a copy of the parameter specified, essentially negating the by-reference semantics of the original object. In order to avoid this, the utility function rwRef() can be used to create an object that will hold the reference and maintain that relationship across copies. This allows a reference to be bound and stored in the binder object created by rwBind().
For example, if a function returns an RWCString through a by-reference argument, this argument can be specified via rwBind() as:
 
void function1(RWCString& out);
 
RWCString result;
RWTFunctor<void()> functor1 = rwBind(function1, rwRef(result));
When functor1 is invoked, function1 will be invoked with a reference to result. Any changes to result will be visible once the functor invocation has completed.
NOTE >> Note: Since the RWTFunctor holds a reference to the object, it is the responsibility of the user to ensure that the lifetime of the referenced object is longer than the lifetime of the binder object. Otherwise, undefined behavior will result if the binder object is invoked.
Binding Member Functions
Along with normal functions, rwBind() also supports binding member functions. When binding member functions, the signature of rwBind() is interpreted slightly differently, as follows:
 
rwBind(<member function>, <object>, <arg type 1>, <arg type 2>, …, <arg type N>)
In this variant, <member function> is a pointer to the member function that will be invoked, <object> is the instance of an object on which <member function> will be invoked, and <arg type 1>, <arg type 2>, …, <arg type N> are the arguments that will be passed to the member function. For example, to create a functor that invokes RWCString::length() on an RWCString instance, you could use the following:
 
RWCString str;
RWTFunctor<size_t()> functor1 =
rwBind(&RWCString::length, rwRef(str));
When functor1 is invoked, it will invoke the equivalent of:
 
str.length();
Using Placeholder Arguments
In some situations it may be useful to specify some of the arguments when the binder object is being created, and to leave other arguments until the resulting object is invoked. rwBind() supports this scenario through the usage of placeholder objects. A placeholder is an indicator to rwBind() that a particular parameter will be provided when the binder object is invoked instead of when it is constructed. SourcePro C++ uses predefined placeholders of the form rwN, where N is the position of the argument that should be substituted when the binder object is invoked.
For example, assume a function that calculates compound interest:
 
double compound(double principle, double interest, int periods) {
return principle * pow(1 + interest, periods);
}
If we simply wanted to wrap this in a functor, we could do so using:
 
RWTFunctor<double(double, double, int)> functor1 = compound;
The resulting functor could then be invoked as:
 
functor1(1000.0, 0.01, 5); // -> 1051.01
We can also bind all of the arguments when the functor is being created using rwBind():
 
RWTFunctor<double()> functor2 = rwBind(compound, 500.0, 0.05, 5);
The resulting functor could then be invoked as:
 
functor2(); // -> 638.141
With placeholders, we can choose to bind only some of the parameters at creation. For instance, if we know what our principle will be, but would like to invoke the functor with different interest rates and periods, we can create a functor as:
 
RWTFunctor<double(double, int)> functor3 =
rwBind(compound, 100.0, rw1, rw2);
The resulting functor can then be invoked with the two parameters that were specified as placeholders:
 
functor3(0.10, 10); // -> 259.374
Along with changing whether a parameter is provided when the functor is created or when it is invoked, placeholders can also adapt a callee signature to match the signature a functor expects. For example, a functor could be defined to expect the parameters of compound() in a different order (periods, principle, interest). Placeholders can be used to adjust the order of parameters:
 
RWTFunctor<double(int, double, double)> functor4 =
rwBind(compound, rw2, rw3, rw1);
The new functor can now be invoked with parameters in a different order than compound() expects, and the binder object takes care of mapping them appropriately:
 
functor4(5, 1000.0, 0.01); // -> 1051.01 (same result as functor1)
 
While placeholders are sequential, they don't necessarily all need to be referenced in the binder. Parameters can be ignored by omitting a placeholder for that argument from the rwBind() call. For example, a functor could be defined that expects an additional parameter (char) indicating the equation to use; however, since we have only one implementation, that parameter can be ignored:
 
RWTFunctor<double<char, double, double, int)> functor5 =
rwBind(compound, rw2, rw3, rw4);
When the functor is invoked, the first parameter (char) is ignored since rw1 was not specified when rwBind() was invoked.
 
functor5('c', 1000.0, 0.01, 5); // -> 1051.01 (same result as functor1)
Placeholders can also occur more than once in an rwBind() call, allowing a single caller parameter to be passed as multiple parameters to the callee. For example, assume a function for calculating the area of a rectangle (with parameters for height and width):
 
double area(double height, double width);
This function could be adapted to work with a functor that works with squares, and specifies only a single dimension:
 
RWTFunctor<double(double)> functor6 = rwBind(area, rw1, rw1);
The resulting functor can then be invoked with a single dimension, returning the area of a square with that dimension:
 
functor6(10); // -> 100