Tuesday, April 06, 2010

Bind illustrated

Asynchronous operations in Asio all expect a function object argument, the completion handler, which they invoke when the asynchronous operation completes. The signature of the handler depends on the type of operation. For example, a handler posted using io_service::post() must have the signature:

void handler();

while an asynchronous wait operation expects:

void handler(error_code ec);

and asynchronous read/write operations want:

void handler(error_code ec, size_t length);

Non-trivial applications will need to pass some context to the completion handler, such as a this pointer. One way to do this is to use a function object adapter like boost::bind, std::tr1::bind or (as of C++0x) std::bind.

Unfortunately, for many C++ programmers, bind represents a little bit of magic. This is not helped by the impenetrable compiler errors that confront you when you use it incorrectly. And, in my experience, the underlying concept (where some function arguments are bound up-front, while others are delayed until the point of call) can present quite a steep learning curve.

I have put together some diagrams to help explain how bind works. For clarity, I have taken a few liberties with C++ syntax (e.g. omitting the parameter types on the function call operator) and (over-)simplified bind's implementation. Finally, the examples are limited to those likely to be useful with Asio. Comments and suggestions welcome.


bind can be used to adapt a user-supplied function expecting one argument into a function object that takes zero arguments. The bound value (123 in this example) is stored in a function object and is automatically passed to the user-supplied function as required:


[ click images for full size ]

Binding an argument can be used to turn a class member function into a zero-argument function object. As you know, non-static member functions have an implicit this parameter. This means that an appropriate pointer needs to be bound into the function object:


Alternatively, the implicit this can be made explicit by adapting a member function into a function object taking one argument:


Function objects will often use both bound arguments and arguments supplied at the point of use. This can be done using member functions:


or non-member functions:


Sometimes the function object's point of use will supply arguments which are not required to call the target function. bind will automatically discard these surplus arguments:


The surplus argument(s) need not be the at the end of the function object signature:


Finally, bind allows you to the reorder arguments to adapt the target function to the necessary function object signature:

13 comments:

Anonymous said...

A picture is worth a thousand words. Well done. Thank you!

Sébastien Taylor said...

The high volume of posts last few weeks have been great, much appreciated and keep'em coming!

Benjamin van den Hout said...

Excellent explanation, thank you! Looking forward to more postings :)

Anonymous said...

Please, add some words about yours box() function (with diagrams for the nested binds).

Simon said...

Thanks for the pictures, that's what I was looking for as the bind documentation is somewhat unclear.

So? said...

Excellent!

Ralf said...

Wow, excellent article! Those diagrams are fantastic and really clarify a lot of things. Thanks Chris

Sonic said...

may i ask what software did you use to create the diagrams?

Anders Sjögren said...

Thanks for the summary. It'd be interesting to see how C++11 lambdas compare to bind. In particular, in what situations is bind preferred, and why?

Anonymous said...

I've a little question :

when we bind some member fn pointer to this pointer . doesn't bind has to figure out the first parameter arg is normal function pointer or member fn pointer so that it binds member fn pointer to this pointer correctly?

can you also explain how does correct interpretation takes place?

Richy said...

Sometimes three year old posts are really helpful!
Thanks a lot!

Anonymous said...

Thanks for being one of those who care for people and mankind.
I'd like to be one of you.

Anonymous said...

Thank you so much! Excellent article!