Quick Links: |
Provide signature-specific function objects (functors). More...
Components | |
Component bdlf_bind | |
Provide a signature-specific function object (functor). | |
Component bdlf_memfn | |
Provide member function pointer wrapper classes and utility. | |
Component bdlf_placeholder | |
Provide a parameterized placeholder and specialized placeholders. |
bdlf
package provides components to implement function objects (functors) that return void and take between zero and nine arguments of arbitrary type. Function objects created by bdlf
components can be invoked in a manner similar to that of the following free function: void functionObject(arglist);
arglist
contains between zero and nine arguments. Functor classes are differentiated by the number and type of arguments they expect. The bdlf
package contains 10 separate components that differ in the number of arguments their functors expect; within each component, templates are used to support variations in argument type. bdlf_bind
, bdlf_memfn
and bdlf_function
) provide more general functors that can conform to a specified prototype and return an arbitrary type, and that can be invoked in the same manner as before. The functors created by these two components currently support from zero up to 14 arguments. bdlf_bind
provides compile-time polymorphism, and adapts an invocable object so that it conforms to a different interface and can be invoked with fewer arguments and/or with the arguments in a different order. This transformation is type-safe, in that type violations provoke compilation errors. bdlf_memfn
provides a wrapper that allows a member function to be invoked like a free function, either by providing the object instance as first parameter, or by wrapping the object instance inside the function object. bdlf_function
provides run-time polymorphism and is especially suited for callbacks because it adapts any invocable with a compatible prototype to a specified callback interface, at run-time and without the need for recompilation. bdlf
package currently has 3 components having 2 levels of physical dependency. The list below shows the hierarchical ordering of the components. The order of components within each level is not architecturally significant, just alphabetical. 2. bdlf_bind 1. bdlf_memfn bdlf_placeholder
bdlf_bind
: bdlf_memfn
: bdlf_placeholder
: bdlf
is designed to use three other packages in bdl
. bdlf
provides the primary interface that a client will see, and the other packages play supporting roles. bdlf
: bdlfr
: bdlfi
. These classes provide reference counting and object deletion for derived classes.bdlfi
: bdlf
object; classes in bdlfi
implement behavior declared in bdlfr
.bdlfu
: bdlf
functors by creating a reference-counted function object (from bdlfi
) and assigning it to a bdlf
functor. Subsequent invocations of the bdlf
functor will be delegated to the bdlfi
object.bdlf
, bdlfr
, bdlfi
, and bdlfu
packages provide identical functionality to the corresponding packages in the bce
package group: bcef
, bcefr
, bcefi
, and bcefu
, respectively. The difference between the two sets of packages is that the bce
packages provide thread safety, whereas the bdl
packages do not. In particular, package bcefr
implements reference counting via atomic operators provided in package bces_atomicutil
. void (*fp)(int, const char*);
fp
that points to a function returning void
, and taking exactly two arguments, an int
and a const pointer to char
. void f1(int x, const char* s); void f2(int x, const char* s);
fp = f1; . . . int my_x = 0; int my_s = "Text String"; fp(my_x, my_s); // invokes function f1
operator()
) whose signature characterizes the particular functor's type. In this example, for instance, we could define a functor like this: class MyFunctor { // Class MyFunctor can be used like a function. . . . public: void operator()(int x, const char* s); // this provides invocation semantics . . . }; MyFunctor fn; . . . int my_x = 0; int my_s = "Text String"; fn(my_x, my_s); // "invokes" functor fn via fn::operator()
bdlf_vfunc
followed by 0 to 6; the letter v
indicates that the corresponding functor will return void
. For the example above, we would use component bdlf_vfunc2
to create a functor object whose operator()
member function obeys the required signature. #include <bdlf_vfunc2.h> bdlf_Vfunc2<int, const char*> fn; // template arguments specify arg // types // NOTE: This example is incomplete. // We still need code to initialize 'fn' . . . int my_x = 0; int my_s = "Text String"; fn(my_x, my_s); // "invokes" functor fn
bdlf
functor is invoked as illustrated, the client is responsible for ensuring that it is valid; that is, it must contain a pointer to a function that will be called when the functor is invoked. The function to be called is external to the functor, and supplied by the client. This "external
function" may be a free function, a static class method, or a (non-'static') member function for some class. The client, then, needs a canonical mechanism, regardless of the function type, to create a reference to that function, and to bind the reference to the bdlf
functor. bdlfu
package. The bdlfu
package contains 10 components which provide these factory methods. Parallel to bdlf
, these components are "numbered" to support functors with different numbers of arguments. The factory methods are also templatized to support varying argument types. bdlfu
component contains 4 different types of factory methods, varying by the type of function pointer required. For example, bdlfu_vfunc2
defines the following factory method families: bdlfu_Vfunc2::makeF(); // generate a pointer to a free function // and assign it to a 'bdlf_Vfunc2' object bdlfu_Vfunc2::makeM(); // generate a pointer to a member function // and assign it to a 'bdlf_Vfunc2' object bdlfu_Vfunc2::makeC() // generate a pointer to a const member // function and assign it to a 'bdlf_Vfunc2' // object bdlfu_Vfunc2::makeNull(); // initialize a 'bdlf_Vfunc2' object with // an empty function
makeNull
) are templatized to support different return and argument types; in addition, each factory method family consists of a set of overloaded functions that support varying numbers of arguments on the underlying functions (member or free). All classes returned by functions in component bdlfu_vfunc2
are defined in component bdlfi_vfunc2
. See package documentation for the bdlfu
package for details. bdlfu_Vfunc2
as follows to initialize the bdlf_Vfunc2
object: #include <bdlf_vfunc2.h> #include <bdlfu_vfunc2.h> void f1(int x, const char* s); void f2(int x, const char* s); bdlf_Vfunc2<int, const char*> fn; // template arguments define arg types bdlfu_Vfunc2::makeF(&fn,f1); // bind functor fn to function f1 . . . int my_x = 0; int my_s = "Text String"; fn(my_x, my_s); // "invokes" functor fn
bdlfu_Vfunc2::makeF
factory method in the above example expects two arguments. The first is a pointer to the functor object itself, and the second is a pointer to a free function with a signature matching the functor object, that is, expecting args of int
and const char*
, and returning void
. makeF()
functions create instances of classes from the bdlfi
component; the specific classes are determined by the number and types of arguments on the bdlf
functor and the free function. Similarly, class member functions can be used to initialize a bdlf
functor by invoking a bdlfu_Vfunc2::makeM()
or bdlfu_Vfunc2::makeC()
function. bdlfu
and bdlfi
packages will also allow clients to match a functor to a free or member function in situations where the function requires more arguments than the functor invocation can support. See the documentation for package bdlfu
for details describing how to do this; see package documentation for bdlfi
for implementation details. T
is passed by (const
T&
), a compiler will generate an error if the user declares a callback function taking an argument via a non-'const' reference parameter. This is intended to support and enforce the rule that all modifiable arguments are passed using pointers and not using references. For rare situations where clients want to use a callback function supplied by a third party, and that callback function uses non-'const' references, a wrapper function must be declared that converts non-'const' references to const
references or pointers as appropriate. bdlf
package are implemented using the envelope-letter idiom. The classes in bdlf
are "envelopes"; classes in bdlfr
and bdlfi
are "letters". The use of the envelope-letter idiom allows clients to wrap arbitrary functions, whose signatures may differ from the function signatures in bdlf
, with functors that support standard, well-known signatures. bdlf_Vfunc*
functor (envelope) holds a pointer to an object (letter) from the corresponding bdlfi_vfunc*
component. The bdlf
envelope forwards or delegates client requests to its letter object: in particular, the operator()
member function used by clients to invoke the functor is delegated to the letter object for execution. bdlfi
component are derived from a common protocol or abstract base class (defined in bdlfr
). The bdlf
envelope uses the abstract bdlfr
protocol to delegate invocation requests. Different polymorphic letter types are used to support different external function types and signatures, and the single envelope type is used to provide a consistent function signature to clients. bdlfi
component, but in most cases it is simpler to use a suite of template functions provided by the corresponding bdlfu
package. Different template functions are provided to match (1) the desired function-call-operator signature and (2) the supplied user data. Because the C++ compiler will deduce template parameters from argument types, clients need not specify them. See the bdlfu
package for more information on populating bdlf
functors with specific letter objects. bdlf_bind
component provides a mechanism for creating function objects different from the bdlf_vfunc*
components. bdlf_bind
is used to adapt an invocable object so that it conforms to a different interface and can be invoked with fewer arguments and/or with the arguments in a different order. It does this by binding some or all of the original invocable's arguments to fixed values that are known at construction time and binding the remaining arguments to placeholders for arguments that are provided at invocation time. A binder can be used as an argument for any template function that requires an invocable with compatible parameters. bdlf_bind
component defines binder objects and factory methods that can bind any arguments into a functor in any order, enabling some of the arguments of the invocable to be specified at the construction time, and leaving (via place-holders, defined in component bdlf_placeholder
) some others to be specified (later) at invocation time. A binder is created by one of the three factory method families defined in component bdlf_bind
: bdlf_BindUtil::bind(); // generate a binder with specified invocable and // bound arguments (invocation arguments are // indicated by place-holders) bdlf_BindUtil::bindA(); // same as above but also specify the allocator // used to supply memory for creating the binder bdlf_BindUtil::bindR(); // same as 'bdlf_BindUtil::bind()' but explicitly // specify the return type (in case it cannot be // deduced by the compiler but should not be left // undefined)
bdlf_Bind
object is not embedded in the type, and several overloads can be invoked through the same binder. Unlike bdlf_Vfunc*
objects, different binders accepting the same signature may have different types depending on the types of the bound arguments if they are non-explicit. The return type (not necessarily void) is also part of the signature. Thus, bdlf_bind
provides compile-time polymorphism but not run-time polymorphism. bdlf_bind
. bdlf
package provides a run-time polymorphic bdlf_Function
template. A bdlf_Function
instantiation is capable of holding any invocable object of compatible prototype, including a function pointer, bdlf_MemFn
wrapper, any concrete implementation of the 'bdlfr_Vfunc*'protocols, any instances of the bdlf_Vfunc
family, and any other function object having an operator()
method including an instance of a bdlf_Bind
instantiation. bdlf_Function
instantiation can have a return value (or return void
). An instance does not store bound arguments directly. It accepts all its arguments at invocation time only, although using polymorphic representations and the bdlfu_Vfunc*make*
factory methods, it is possible to bind the last arguments of an invocable and wrap this into a bdlf_Function
object which will then accept only the remaining arguments upon invocation. As mentioned above, it is also possible to assign a bdlf_Bind
object to a bdlf_Function
instance to bind and route arguments to the invocable in an arbitrary manner. bdlf_Function
object is part of the type and invocation arguments are cast to their corresponding type before they are passed to the invocable. Most importantly, the same functor may be assigned from various types (pointer to function, bdlf_MemFn
wrapper, user-defined function objects, or even bdlf_Bind
binders). bdlf_Function
objects (functors) and bdlf_Bind
objects (binders) are both mechanisms for binding arguments and calling an invocable. They differ in their purpose, though. In the last section, we detailed the main features of the bdlf_function
and bdlf_bind
components. In this section we point out the differences, and how they interact. bdlf_bind
) vs. run-time (for bdlf_function
) polymorphism. An instantiation of bdlf_Function
is a type of functor that can hold any invocable object with compatible prototype. Regardless of what type of (compatible) invocable is used to create the bdlf_Function
, the type of the resulting functor does not change. Thus, bdlf_Function
has run-time polymorphism and is ideally suited for callbacks because it adapts the invocable to the callback interface. Run-time polymorphism is extremely useful for defining callback types and storing callbacks, since passing a new type of callback does not require re-compilation. Compile-time polymorphism provides the ability to invoke several overloads through the same functor (binder) and to bind and route arguments to the invocable in an arbitrary manner. bdlf_Function
has certain advantages, not least of which is simplicity (leading to shorter compilation times), and the memory optimization documented below, whereby small objects are constructed in-place but larger objects are dynamically allocated. Note that binders are always constructed in-place and can have rather large footprints. Functors (including instances of bdlfr_Vfunc*
derived types) can implement various strategies like sharing and copy-on-write to reduce the cost of copying and the footprint at the same time. bdlf
-style functors provide a type-neutral, exception-safe (and potentially, but not yet, thread-safe) properly managed alternative to the traditional callback paradigm (where "client data" is placed in a single structure whose address is cast to type void *
). The following example illustrates how functor callbacks can be added to a graphical object. MyGuiButton
class allows the client to specify a callback function that should be called whenever a button is pressed. Furthermore, the implementor agrees to provide to the callback function two arguments at its invocation: a modifiable object of type MyGuiContext
, and a non-modifiable object of type MyGuiLocation
. class MyGuiContext { int d_changedFlag; public: MyGuiContext() : d_changedFlag(0) { } int isChanged() { return d_changedFlag; } void changeState() { ++d_changedFlag; } // 'MyGuiContext' implementation }; class MyGuiLocation { public: MyGuiLocation() { }; // 'MyGuiLocation' implementation };
MyGuiButton
class: class MyGuiButton { bdlf_Vfunc2<MyGuiContext *, MyGuiLocation> d_callback; // Functor to execute when button is pressed. public: MyGuiButton(const bdlf_Vfunc2<MyGuiContext *, MyGuiLocation>& buttonPressCallback); // Create a graphical button object that executes the // specified callback when 'pressButton' is invoked. void pressButton(MyGuiContext *context, const MyGuiLocation& location); // Execute the callback owned by this button object. }; MyGuiButton::MyGuiButton(const bdlf_Vfunc2<MyGuiContext *, MyGuiLocation>& buttonPressCallback) : d_callback(buttonPressCallback) // Retain a "copy" of the specified // functor. { } void MyGuiButton::pressButton(MyGuiContext *context, const MyGuiLocation& location) { d_callback(context, location); // Execute the contained callback object. }
context
and location
arguments are mandatory for every function called at the press of the button (the number 2
in the name of bdlf_Vfunc2
class specifies the number of required arguments). However, we also allow the user of MyGuiButton
class to invoke the function with a number of additional parameters, as in the buttonpressFunction
function presented below. static void buttonpressFunction(MyGuiContext *a, const MyGuiLocation& b, int *invocationCounter) // This function will be invoked by a functor to increment the // specified 'invocationCounter'. { a->changeState(); ++*invocationCounter; }
bdlf_Vfunc2<MyGuiContext, MyGuiLocation>
class used in MyGuiButton
class has a private member of an abstract class bdlfr_vfunc2
, whose execute
method is called when the functor is being called. The execute
method of the bdlfr_vfunc2
class, the functor invocation operator of the bdlf_Vfunc2
class, and the pressButton
method of MyGuiButton
class have two parameters. The buttonpressFunction
callback function, however, has to be called with three arguments. To achieve the proper calling signature the user implements a concrete class derived from bdlfr_vfunc2
as follows: template <class F, class A1, class A2, class D1> class FuncRep : public bdlfr_Vfunc2<A1, A2> { // This class defines the representation for a function object (functor), // characterized by a function-call operator taking two arguments and // returning 'void', that holds a pure procedure (i.e., free function, // static member function, or functor) taking one additional trailing // argument, and this argument's corresponding value. F d_f; // function pointer or function object (functor) D1 d_d1; // first embedded argument private: // not implemented FuncRep(const FuncRep<F, A1, A2, D1>&); FuncRep<F, A1, A2, D1>& operator=(const FuncRep<F, A1, A2, D1>&); private: ~FuncRep() // Destroy this functor. Note that destructor can be invoked only // through the static 'deleteObject' method of the base class. { }; public: // CREATORS FuncRep(const F& procedure, const D1& embeddedArg1, bdlma_Allocator *basicAllocator) // Create a representation for a function object (functor) taking two // arguments and returning 'void', using the specified 'procedure' // taking 1 additional trailing argument, and this argument's // specified 'embeddedArg1' value. Use the specified // 'basicAllocator' to supply memory. : bdlfr_Vfunc1<A1, A2>(basicAllocator) , d_f(procedure) , d_d1(embeddedArg1) { }; // ACCESSORS void execute(const A1& argument1, const A2& argument2) const // Invoke the underlying procedure (free function, static member // function, or functor) with the specified 'argument1' and // 'argument2' followed by the argument value specified at // construction. { d_f(argument1, argument2, d_d1); }; };
MyGuiButton
interface, and hence will never change. MyGuiButton
class. // (1) Create the representation. typedef void (*BpFun)(const MyGuiContext *, const MyGuiLocation&, int *); bdlma_Allocator *myAllocator = bdlma_Default::defaultAllocator(); int globalCounter = 0; bdlfr_Vfunc2<MyGuiContext *, MyGuiLocation> *rep = new(myAllocator) FuncRep<BpFun, MyGuiContext *, MyGuiLocation, int*> (buttonpressFunction, &globalCounter, myAllocator); // (2) Create the functor using the representation. bdlf_Vfunc2<MyGuiContext *, MyGuiLocation> callbackFunctor(rep); // (3) Register the functor as a callback. MyGuiButton button(callbackFunctor); // (4) Use the object. MyGuiContext gc; const MyGuiLocation gl; assert(0 == globalCounter); assert(0 == gc.isChanged()); button.pressButton(&gc, gl); assert(1 == globalCounter); assert(1 == gc.isChanged()); button.pressButton(&gc, gl); assert(2 == globalCounter); assert(2 == gc.isChanged());