BDE 4.14.0 Production release
Loading...
Searching...
No Matches

Macros

#define BDLF_BIND_PARAMINDEX(N)
 
#define BDLF_BIND_EVAL(N)
 

Detailed Description

Outline

Purpose

Provide a signature-specific function object (functor).

Classes

See also
bdlf_memfn, bdlf_placeholder

Description

This component provides a parameterized binder mechanism, bdlf::Bind, that is a functor object that binds an invocable object or function to a list of arguments. This component also defines factory methods in the bdlf::BindUtil namespace for creating bdlf::Bind objects (e.g., bind and bindR) and bdlf::BindWrapper objects (e.g., bindS and bindSR). The bdlf::Bind functor (called henceforth a "binder") is an object that can hold any invocable object (the "bound functor") and a number of parameters (the "bound arguments", some of which can be place-holders of type bdlf::PlaceHolder). When the binder is later invoked (with optional additional arguments called the "invocation arguments" used to compute the value of bound arguments that use place-holders), it returns the result of calling the bound functor with the bound arguments and invocation arguments. The bdlf::BindWrapper functor provides a binder with shared pointer semantics to a non-modifiable binder (both operator* and operator-> accessors) and forwards its construction arguments to the underlying binder. The section "Supported functionality and limitations" details which kind of bound functors and bound arguments can be used in conjunction with this component.

The main use of bdlf::Bind is to invoke bound functors with additional data that is not available prior to the point the functor is invoked (as is often the case with callback functions). The binding is accomplished by passing place-holders instead of literal values as the bound arguments. When the binder is invoked, these place-holders are replaced by their respective invocation arguments. The section "Elementary construction and usage of bdlf::Bind objects" shows an elementary (but not realistic) usage of the bdlf::BindUtil::bind factory methods with free functions, that should be enough for most users to grasp the basic usage of this component. The section "Binding data" offers more details and should enable a user to make a more advanced usage of this component. The usage example presents many uses of bdlf::Bind and bdlf::BindUtil in a somewhat realistic (but a bit more involved) situation.

Note that bdlf::Bind functors are typically used with standard algorithms, or with bsl::function. This mechanism is similar to, but much more powerful than, bsl::bind1st or bsl::bind2nd.

The difference between a binder created using one of bindS and bindSR and a binder created using bind, and bindR is that in the former case the binder is returned by reference rather than by value, with shared ownership semantics. Hence its main use is for creating binders that hold a non-trivial amount of storage (i.e., the bound arguments) and will be copied, possibly several times, such as jobs enqueued in a threadpool.

Supported Functionality

An invocable object is any object that can be invoked in syntactically the same manner as a function. Invocable objects include function pointers, and objects that provide an operator() method. This component supports bound objects that can be function pointers, member function pointers (the first bound argument must evaluate to an instance of the class of which the function is a member), or function objects passed by address or by value. In addition, there is a limitation on the number of parameters that such an object can take (currently no more than 14).

A bdlf::Bind functor can be constructed, usually by one of the bdlf::BindUtil factory methods, from a bound functor and from 0 up to 14 bound arguments that can be either literal values, place-holders of type bdlf::PlaceHolder, or further bdlf::Bind functors. The type of a binder object is a complicated expression, which is why a binder is typically a short-lived object that is returned or passed as parameter to a function template. That is also why the bdlf::BindUtil factory methods are the preferred way to create a binder. When a binder is later invoked with some arguments, literal values are passed to the bound functor and place-holders are substituted by their respective invocation arguments. In addition, any argument that is a binder itself is invoked recursively with the same invocation arguments and the result of that invocation is passed to the parent binder. The section "Elementary construction and usage of bdlf::Bind objects" below details the whole mechanism and offers some examples.

The bdlf::Bind functors support bslma::Allocator * arguments. When binders are constructed by the bdlf::BindUtil::bind (and bindR) factory methods, the currently installed default allocator is used. When binders are constructed by the bdlf::BindUtil::bindS (and bindSR) factory methods, the non-optional, user-supplied allocator is used both for the creation of the bound functor arguments and for the reference counting mechanism that manages those arguments. See the section "Binding with allocators" below for a more detailed discussion.

Elementary Construction and Usage of bdlf::Bind Objects

Bound functors are generally constructed by invoking the bdlf::BindUtil with an "invocation template". An invocation template is a series of one or more arguments that describe how to invoke the bound functor. Each argument can be either a place-holder or a literal value. Literal values are stored by value in the binder and directly forwarded to the bound functor when invoked. Place-holders are substituted with the respective argument provided at invocation of the binder. For example, given the following invocable (here a free function for simplicity):

void invocable(int i, int j, const char *str)
{
// Do something with 'i', 'j' and 'str'.
printf("Invoked with: %d %d %s\n", i, j, str);
}

and the following (global) string:

const char *someString = "p3"; // for third parameter to 'invocable'

we can bind the parameters of invocable to the following arguments:

void bindTest(bslma::Allocator *allocator = 0) {
bdlf::BindUtil::bind(&invocable, // bound functor and
10, 14, someString) // bound arguments
static Bind< bslmf::Nil, t_FUNC, Bind_BoundTuple0 > bind(t_FUNC func)
Definition bdlf_bind.h:1830
Definition bslma_allocator.h:457

and the binder declared above can be passed invocation arguments directly, as follows (here we specify zero invocation arguments since all the bound arguments are fully specified):

(); // invocation

Similarly, we can also create a reference-counted shared binder using the bindS method:

bdlf::BindUtil::bindS(allocator, // allocator,
&invocable, // bound object and
10, 14, (const char*)"p3")(); // bound arguments
}
static BindWrapper< bslmf::Nil, t_FUNC, bdlf::Bind_BoundTuple0 > bindS(bslma::Allocator *allocator, t_FUNC func)
Definition bdlf_bind.h:3087

In the function call above, the invocable will be bound with the arguments 10, 14, and "p3" respectively, then invoked with those bound arguments. In the next example, place-holders are used to forward user-provided arguments to the bound functor. We separate the invocation of the binder into a function template to avoid having to declare the type of the binder:

template <class BINDER>
void callBinder(BINDER const& b)
{
b(10, 14);
}

The creation of the binder is as follows:

void bindTest1(bslma::Allocator *allocator = 0) {
callBinder(bdlf::BindUtil::bind(&invocable,
_1, _2, someString));
callBinder(bdlf::BindUtil::bindS(allocator,
&invocable,
_1, _2, someString));
}

In this code snippet, the callBinder template function is invoked with a binder bound to the specified invocable and having the invocation template _1, _2, and "p3" respectively. The two special parameters _1 and _2 are place-holders for arguments one and two, respectively, which will be specified to the binder at invocation time. Each place-holder will be substituted with the corresponding positional argument when invoked. When called within the callBinder function, invocable will be invoked as follows:

invocable(10, 14, "p3");

Place-holders can appear anywhere in the invocation template, and in any order. The same place-holder can appear multiple times. Each instance will be substituted with the same value. For example, in the following snippet of code, the callBinder function, is invoked with a binder such that argument one (10) of the binder is passed as parameter two and argument two (14) is passed as (i.e., bound to) parameter one:

void bindTest2(bslma::Allocator *allocator = 0) {
callBinder(bdlf::BindUtil::bind(&invocable, _2, _1, someString));
callBinder(bdlf::BindUtil::bindS(allocator,
&invocable,
_2, _1, someString));
}

When called within the callBinder function, invocable will be invoked as follows:

invocable(14, 10, "p3");

The following snippet of code illustrates a number of ways to call bdlf::BindUtil and their respective output:

int test1(int i, int j)
{
return i + j;
}
int abs(int x)
{
return (x > 0) ? x : -x;
}
void bindTest3(bslma::Allocator *allocator = 0)
{
using namespace bdlf::PlaceHolders;
assert(24 == bdlf::BindUtil::bind(&test1, _1, _2)(10, 14));
assert(24 == bdlf::BindUtil::bind(&test1, _1, 14)(10));
assert(24 == bdlf::BindUtil::bind(&test1, 10, _1)(14));
assert(24 == bdlf::BindUtil::bind(&test1, 10, 14)());
assert(24 == bdlf::BindUtil::bind(&test1,
bdlf::BindUtil::bind(&abs,_1), 14)(-10));
assert(24 == bdlf::BindUtil::bindS(allocator, &test1, _1, _2)(10, 14));
assert(24 == bdlf::BindUtil::bindS(allocator, &test1, _1, 14)(10));
assert(24 == bdlf::BindUtil::bindS(allocator, &test1, 10, _1 )(14));
assert(24 == bdlf::BindUtil::bindS(allocator, &test1, 10, 14)());
assert(24 == bdlf::BindUtil::bindS(allocator, &test1,
bdlf::BindUtil::bindS(allocator, &abs, _1), 14)(-10));
}
Definition bdlf_placeholder.h:82

The usage example below provides a more comprehensive series of calling sequences.

Binding Data

The main use of bdlf::Bind is to invoke bound functors with additional data that is not available prior to the point the functor is invoked (as is often the case with callback functions). For that purpose, place-holders are key. There are a couple of issues to understand in order to properly use this component. The bound arguments must be of a value-semantic type (unless they are place-holders or bdlf::Bind objects). They are evaluated at binding time once and only once and their value copied into the binder (using the default allocator to supply memory unless an allocator is specified). A bdlf::Bind object always invokes its bound functor with only the arguments listed as bound arguments, regardless of how many arguments are specified to the binder at invocation time. Invocation arguments that are not referenced through a place-holder are simply discarded. Invocation arguments that are duplicated (by using the same place-holder several times) are simply copied several times. The following examples should make things perfectly clear.

Ignoring Parameters

It is possible to pass more invocation arguments to a binder than were specified in the signature by the number of bound arguments. Invocation arguments not referenced by any placeholder, as well as extra invocation arguments, will be ignored. Note that they will nevertheless be evaluated even though their value will be unused. Consider, for example, the following snippet of code:

int marker = 0;
int singleArgumentFunction(int x) {
return x;
}
int identityFunctionWithSideEffects(int x)
{
printf("Calling 'identityFunctionWithSideEffects' with %d\n", x);
marker += x;
return x;
}
template <class BINDER>
void callBinderWithSideEffects1(BINDER const& binder)
{
ASSERT(14 == binder(identityFunctionWithSideEffects(10), 14));
}
void bindTest4(bslma::Allocator *allocator = 0) {
marker = 0;
callBinderWithSideEffects1(bdlf::BindUtil::bind(
&singleArgumentFunction, _2));

In the above snippets of code, singleArgumentFunction will be called with only the second argument (14) specified to the binder at invocation time in the callBinderWithSideEffects1 function. Thus the return value of the invocation must be 14. The identityFunctionWithSideEffects(10) will be evaluated, even though its return value (10) will be discarded. We can check this as follows:

assert(10 == marker);

We repeat the same call using bindS below:

marker = 0;
callBinderWithSideEffects1(bdlf::BindUtil::bindS(
allocator,
&singleArgumentFunction,
_2));
assert(10 == marker);
}

Duplicating Parameters

A place-holder can be specified multiple times, effectively passing the same value to different arguments of the function. The value will be evaluated only once. To illustrate this, consider another example that reuses the singleArgumentFunction of the previous example:

int doubleArgumentFunction(int x, int y) {
return x+y;
}
template <class BINDER>
void callBinderWithSideEffects2(BINDER const& binder)
{
const int RET1 = binder(10);
ASSERT(20 == RET1);
const int RET2 = binder(identityFunctionWithSideEffects(10));
ASSERT(20 == RET2);
}
void bindTest5(bslma::Allocator *allocator = 0) {
marker = 0;
callBinderWithSideEffects2(bdlf::BindUtil::bind(
&doubleArgumentFunction, _1, _1));

In the above snippet of code, doubleArgumentFunction will be called with the first argument (identityFunctionWithSideEffects(10)) specified to the binder, computed only once at invocation time. We can check this as follows:

assert(10 == marker);

We repeat the same call using bindS below:

marker = 0;
callBinderWithSideEffects2(bdlf::BindUtil::bindS(
allocator,
&doubleArgumentFunction,
_1, _1));
assert(marker, 10 == marker);
}

Bound Functors

There are a few issues to be aware of concerning the kind of bound functors that can successfully be used with this component.

Binding to Member Functions

Although member function pointers are not invoked in syntactically the same manner as free functions, they can still be used directly in conjunction with bdlf::Bind. When the binder detects that a member function pointer was specified, it automatically wraps it in a bdlf::MemFn object. In this case a pointer to the object must be passed as the first argument to bind, followed by the remaining arguments. See the usage example "Binding to Member Functions" below.

Note that special care should be exercised when passing this to bind. If this is passed as the first argument to bind, then all other arguments must be passed by value or by const reference.

Binding to Functions with an Ellipsis

It is possible to create a binder with a free function (pointer or reference) that takes an ellipsis (e.g., int printf(const char*, ...). This component does not support ellipsis in member function pointers, however. See the bindTest7 example function at the end of the usage example below.

Binding to Function Objects by Value or by Address

Although function objects are invoked in syntactically the same manner as free functions, they can be used by value or by address in conjunction with bdlf::Bind. When the binder detects that a pointer to a function object was specified, it automatically dereferences that pointer prior to invoking the function object. The difference between the two usages is that the binder object holds a copy of the whole object or of its address only. In particular, when passing by value an object that takes an allocator, the copy held by the binder uses the default allocator if constructed by bdlf::BindUtil::bind or bdlf::BindUtil::bindR, not the allocator of the original object.

For keeping the same allocator, pass the object by address to the binder, or call bindS or bindSR instead. See the section "Binding with allocators" and the usage example sections "Binding to Function Objects" and "Binding to Function Objects by Reference" below.

CAVEAT: When passing a function object by value, only the (non-modifiable) copy held by the binder will be invoked. Prior to this version, it was possible to modifiably invoke this copy (hence a non-const operator()) with the intent to modify the state of the function object. However, only the copy held by the binder was modified and the original function object passed to the binder was not, but this usage error went undetected. In this version, a binder cannot modifiably invoke functors held by value, and attempting to do so will trigger a compilation error. If it is desired that an invocation modifies the state of the function object, then this function object must be passed to the binder by address.

Inferring the Signature of the Bound Functor

When binding a function pointer or class method pointer, the pointer passed must unambiguously refer to a a single overload. When binding a functor object, it is possible for the choice of method overload called to be deferred until invocation.

A bdlf::Bind object will strive to properly and automatically resolve the signature of its bound functor between different overloads of that invocable. The signature of the bound functor is inferred from that of the bound functor and the type of the arguments either at binding or invocation time. The signature of invocables that are not function objects (i.e., free functions with C++ linkage and member functions) must be determined at binding time (in particular, overloads must be disambiguated when obtaining the address of the function). In those cases, the bound arguments will be of the corresponding type and any values passed as bound arguments (except placeholders) will be cast to the corresponding type at binding time and stored by value unless the argument type is a reference type.

Invocation arguments will be cast in place of their corresponding place-holder(s) to the corresponding type only at invocation time. If the signature of the bound functor is known, the invocation argument will be forwarded using the most efficient type (in particular, unnecessary copies will be avoided for non fundamental types).

Some invocable objects, however, may not allow the binder to detect their signature until invocation. This is the case for function objects, for free functions with C linkage (e.g., printf), if a bound argument is a nested binder, or if a placeholder is used in two positions in the bound arguments. In that case, the bound arguments are stored in their own types, and cast to the corresponding argument type of the signature only when the signature is determined at invocation time. Place-holders, likewise, are not typed and will acquire the type of their corresponding invocation argument when invoked, which will be cast to the corresponding argument type of the signature. In particular, the same binder constructed with a functor and place-holders in place of the bound arguments can invoke several overloads of the operator() of the functor, depending on the type of the invocation arguments.

Although function objects are invoked in syntactically the same manner as free functions, their return type cannot always be inferred. The same limitation applies to free functions with extern "C" linkage. In that case, the return type has to be given explicitly to the binder. This can be done by using the bdlf::BindUtil::bindR function. Note that all bsl::function objects have a standard public type result_type to assist the deduction of return type and can be used with bdlf::BindUtil::bind. See the usage example "Binding to a Function Object with Explicit Return Type" below.

Binding with Constants and Temporaries

Due to a technical restriction of the C++ language known as the "forwarding problem", it is not possible to match the signature of a function object exactly when passing a mix of non-const lvalues and rvalues as invocation arguments. Nevertheless, this component supports passing literal values and temporaries as invocation arguments to a bdlf::Bind object. There is however one limitation: if any of the arguments in the signature of the bound functor should be of a modifiable reference type, then all the invocation arguments need to be modifiable references. That is, it is not possible to pass a literal (const) value to some argument of a bound functor when another argument expects a modifiable reference. Note that a direct call to the bound functor (without the binder) would accept such an argument. This is not a severe limitation, and the workaround is to pass instead a local modifiable variable initialized to the literal value.

Binding with Allocators

The bound functor and bound arguments are created as members of the bdlf::Bind object, so no memory is allocated for storing them. However, if the bound functor or bound argument's copy constructor requires memory allocation, that memory is supplied by the currently installed default allocator unless bdlf::BindUtil::bindS (or bindSR) method is used. In the latter cases, the non-optional, user-supplied allocator is passed to the copy constructors of the bound functor and arguments.

When invoking a bound functor object, the (unbound) arguments are passed "as is" to the bound functor. Those arguments are not copied if the bound functor takes them by modifiable or non-modifiable reference.

In order to make clear where the allocation occurs, we will wrap "p3" into a type that takes an allocator, e.g., a class MyString (kept minimal here for the purpose of exposition):

class MyString {
// PRIVATE INSTANCE DATA
bslma::Allocator *d_allocator_p;
char *d_string_p;
public:
// TRAITS
//CREATORS
MyString(const char *str, bslma::Allocator *allocator = 0)
: d_allocator_p(bslma::Default::allocator(allocator))
, d_string_p((char*)d_allocator_p->allocate(1 + strlen(str)))
{
strcpy(d_string_p, str);
}
MyString(MyString const& rhs, bslma::Allocator *allocator = 0)
: d_allocator_p(bslma::Default::allocator(allocator))
, d_string_p((char*)d_allocator_p->allocate(1 + strlen(rhs)))
{
strcpy(d_string_p, rhs);
}
~MyString() {
d_allocator_p->deallocate(d_string_p);
}
// ACCESSORS
operator const char*() const { return d_string_p; }
};
#define BSLMF_NESTED_TRAIT_DECLARATION(t_TYPE, t_TRAIT)
Definition bslmf_nestedtraitdeclaration.h:231
virtual void deallocate(void *address)=0
Definition balxml_encoderoptions.h:68
Definition bslma_usesbslmaallocator.h:343

We will also use a bslma::TestAllocator to keep track of the memory allocated:

void bindTest6() {
MyString myString((const char*)"p3", &allocator);
const Int64 NUM_ALLOCS = allocator.numAllocations();
Definition bslma_testallocator.h:384
bsls::Types::Int64 numAllocations() const
Definition bslma_testallocator.h:1081

To expose that the default allocator is not used, we will use a default allocator guard, which will re-route any default allocation to the local defaultAllocator:

bslma::TestAllocator defaultAllocator("Default", globalVerbose);
bslma::DefaultAllocatorGuard defaultAllocatorGuard(&defaultAllocator);
const Int64 NUM_DEFAULT_ALLOCS = defaultAllocator.numAllocations();
Definition bslma_defaultallocatorguard.h:186

We now create a shared binder object with allocator using bindS:

callBinder(
bdlf::BindUtil::bindS(&allocator, &invocable, _1, _2, myString));

When the bound object is an instance of a class taking an allocator, then allocator is be passed to its copy constructor as occurs in this example. Here allocator is used to make the copy of myString held by the binder.

We now check that memory was allocated from the test allocator, and none from the default allocator:

assert(NUM_ALLOCS != allocator.numAllocations());
assert(NUM_DEFAULT_ALLOCS == defaultAllocator.numAllocations());
}

Usage

This section illustrates intended use of this component.

Example 1: Implementing a Callback

What follows is a series of code snippets illustrating detailed aspects of typical usage of bdlf::Bind and bdlf::BindUtil. For these examples, we will use a typical pair of event and event dispatcher classes, where the event is defined as:

struct MyEvent {
// Event data, for illustration purpose here:
int d_value;
MyEvent() : d_value(0) {}
};

and the event dispatcher is defined as follows:

class MyEventDispatcher {
// This class owns a callback function object that takes an 'int' and
// an instance of 'MyEvent'. When the 'dispatch' method is called, it
// invokes the callback with a series of events that it obtains using
// its own stream of events.
// PRIVATE INSTANCE DATA
bsl::function<void(int, MyEvent)> d_callback;
// PRIVATE MANIPULATORS
int getNextEvent(MyEvent *eventBuffer) {
// Create a copy of the next event in the specified 'eventBuffer'
// Return 0 on success, and non-zero if no event is available.
// Implementation elided
// ...
}
Forward declaration.
Definition bslstl_function.h:934

A dispatcher is created with a callback function object as follows:

public:
// CREATORS
MyEventDispatcher(bsl::function<void(int, MyEvent)> const& cb)
: d_callback(cb)
{
}

and its main function is to invoke the callback on the series of events as obtained by getNextEvent:

// MANIPULATORS
void dispatch(int id)
{
MyEvent e;
while (!getNextEvent(&e)) {
d_callback(id, e);
}
}
};

Example 2: Binding to Free Functions

We illustrate how to use the dispatcher with free callback functions that have various signatures by passing a binder as the callback function of the dispatcher, and how to use the binder to match the signature of the callback function. Note that at the point of invocation in dispatch the binder will be invoked with two invocation arguments, thus we may use only place-holders _1 and _2. In the following snippet of code, the binder passes its invocation arguments straight through to the callback:

void myCallback(int id, MyEvent const& event)
{
// Do something ...
}
void myMainLoop(bslma::Allocator *allocator = 0)
{
MyEventDispatcher schedA(bdlf::BindUtil::bind(&myCallback, _1, _2));
schedA.dispatch(10);
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
&myCallback, _1, _2));
schedB.run(10);
}

Next we show how to bind some of the callback arguments at binding time, while letting the invocation arguments straight through to the callback as the first two arguments:

void myCallbackWithUserArgs(int id,
MyEvent const& event,
int userArg1,
double userArg2)
{
// Do something ...
}
void myMainLoop2(bslma::Allocator *allocator = 0)
{
MyEventDispatcher schedA(bdlf::BindUtil::bind(&myCallbackWithUserArgs,
_1, _2, 360, 3.14));
schedA.dispatch(10);
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
&myCallbackWithUserArgs,
_1, _2, 360, 3.14));
schedB.run(10);
}

In the next snippet of code, we show how to reorder the invocation arguments before they are passed to the callback:

void myCallbackWithUserArgsReordered(int id,
int userArg1,
double userArg2,
MyEvent const& event)
{
// Do something ...
}
void myMainLoop3(bslma::Allocator *allocator = 0)
{
MyEventDispatcher schedA(bdlf::BindUtil::bind(
&myCallbackWithUserArgsReordered, _1, 360, 3.14, _2));
schedA.dispatch(10);
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
&myCallbackWithUserArgsReordered, _1, 360, 3.14, _2));
schedB.run(10);
}

And finally, we illustrate that the signature of the callback can be smaller than expected by the dispatcher by letting the binder ignore its first argument:

void myCallbackThatDiscardsResult(MyEvent const& event)
{
// Do something ...
}
void myMainLoop4(bslma::Allocator *allocator = 0)
{
MyEventDispatcher schedA(bdlf::BindUtil::bind(
&myCallbackThatDiscardsResult, _2));
schedA.dispatch(10);
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
&myCallbackThatDiscardsResult, _2));
schedB.run(10);
}

Example 3: Binding to Function Objects

In the next example, we wrap the callback function into a function object which is bound by value. For brevity, we only present the basic example of passing the arguments straight through to the actual callback operator(), but all the variations of the previous example could be given as well.

struct MyCallbackObject {
typedef void ResultType;
void operator() (int id, MyEvent const& event) const
{
myCallback(id, event);
}
};
void myMainLoop5(bslma::Allocator *allocator = 0)
{
MyCallbackObject objA;
MyEventDispatcher schedA(bdlf::BindUtil::bind(objA, _1, _2));
schedA.dispatch(10);
MyCallbackObject objB;
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
objB, _1, _2));
schedB.run(10);
}

Example 4: Binding to Function Objects by Reference

The following example reuses the MyCallbackObject of the previous example, but illustrates that it can be passed by reference as well as by value:

void myMainLoop6(bslma::Allocator *allocator = 0)
{
MyCallbackObject objA;
MyEventScheduler schedA(bdlf::BindUtil::bind(&objA, _1, _2));
schedA.run(10);
MyCallbackObject objB;
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
&objB, _1, _2));
schedB.run(10);
}

When passed by reference, only the address of the function object is copied. Hence the function object must remain valid throughout the lifetime of the binder.

Example 5: Binding to Member Functions

In the next example, we show that the callback function can be a member function, in which case there are three, not two, bound arguments. The first bound argument must be a pointer to an instance of the class owning the member function.

struct MyStatefulObject {
// DATA
// ...
public:
void callback(int, MyEvent const& event)
{
// Do something that may modify the state info...
}
};
void myMainLoop7(bslma::Allocator *allocator = 0)
{
MyStatefulObject objA;
MyEventScheduler schedA(bdlf::BindUtil::bind(
&MyStatefulObject::callback, &objA, _1, _2));
schedA.run(10);
MyStatefulObject objB;
MyEventScheduler schedB(bdlf::BindUtil::bindS(allocator,
&MyStatefulObject::callback, &objB, _1, _2));
schedB.run(10);
}

Example 6: Nesting Bindings

We now show that it is possible to provide a binder as an argument to bdlf::BindUtil. Upon invocation, the invocation arguments are forwarded to the nested binder.

MyEvent annotateEvent(int, MyEvent const& event) {
// Do something to 'event' ...
return event;
}
void myMainLoop8(bslma::Allocator *allocator = 0)
{
MyCallbackObject objA;
MyEventScheduler schedA(
bdlf::BindUtil::bind(&annotateEvent, _1, _2)));
schedA.run(10);
MyCallbackObject objB;
MyEventScheduler schedB(
bdlf::BindUtil::bindS(allocator, &objB, _1,
bdlf::BindUtil::bindS(allocator, &annotateEvent, _1, _2)));
schedB.run(10);
}

Example 7: Binding to a Function Object with Explicit Return Type

When the return type cannot be inferred from the bound functor (using typename t_FUNC::ResultType), the binder needs an explicit specification. This is done by using the bdlf::BindUtil::bindR function template as exemplified below:

typedef void GlobalResultType;
struct MyCallbackObjectWithoutResultType {
GlobalResultType operator() (int id, MyEvent const& event) const
{
myCallback(id, event);
}
};
void myMainLoop9(bslma::Allocator *allocator = 0)
{
MyCallbackObjectWithoutResultType objA;
MyEventScheduler schedA(bdlf::BindUtil::
bindR<GlobalResultType>(objA, _1, _2));
schedA.run(10);
MyCallbackObjectWithoutResultType objB;
MyEventScheduler schedB(bdlf::BindUtil::
bindSR<GlobalResultType>(allocator, objB, _1, _2));
schedB.run(10);
}
Definition bdlf_bind.h:1793
const PlaceHolder< 1 > _1
const PlaceHolder< 2 > _2

Another situation where the return type (in fact, the whole signature) cannot be inferred from the bound functor is the use of the free function with C linkage and variable number of arguments printf(const char*, ...). In the following code snippet, we show how the argument to the callBinder function (redefined below for the reader's convenience) of section "Elementary construction and usage of bdlf::Bind objects" above can be bound to printf:

template <class BINDER>
void callBinder(BINDER const& b)
{
b(10, 14);
}
void bindTest7(bslma::Allocator *allocator = 0)
{
const char *formatString = "Here it is: %d %d\n";
callBinder(bdlf::BindUtil::bindR<int>(&printf, formatString, _1, _2));
}

When called, bindTest7 will create a binder, pass it to callBinder which will invoke it with arguments 10 and 14, and the output will be:

Here it is: 10 14

Macro Definition Documentation

◆ BDLF_BIND_EVAL

#define BDLF_BIND_EVAL (   N)
Value:
t_ARG_TUPLE>::eval(argList, (boundList->d_a##N).value())
Definition bdlf_bind.h:9057
Definition bslmf_typelist.h:1625

◆ BDLF_BIND_PARAMINDEX

#define BDLF_BIND_PARAMINDEX (   N)
Value:
( \
(k_PARAM1 == N ? 1 : 0) + \
(k_PARAM2 == N ? 2 : 0) + \
(k_PARAM3 == N ? 3 : 0) + \
(k_PARAM4 == N ? 4 : 0) + \
(k_PARAM5 == N ? 5 : 0) + \
(k_PARAM6 == N ? 6 : 0) + \
(k_PARAM7 == N ? 7 : 0) + \
(k_PARAM8 == N ? 8 : 0) + \
(k_PARAM9 == N ? 9 : 0) + \
(k_PARAM10 == N ? 10 : 0) + \
(k_PARAM11 == N ? 11 : 0) + \
(k_PARAM12 == N ? 12 : 0) + \
(k_PARAM13 == N ? 13 : 0) + \
(k_PARAM14 == N ? 14 : 0))