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 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