Bronze Bronze - 3 months ago 10
C++ Question

What is occurring at this bind in C++?

I know that this is simple code, but I can't find amazingly detailed documentation anywhere for the project or on C++'s bind. This is the code:

uri.canonize(bind(&FaceController::onCanonizeSuccess, this, _1, onSuccess, onFailure, uri),
bind(&FaceController::onCanonizeFailure, this, _1, onSuccess, onFailure, uri),
m_ioService, TIME_ALLOWED_FOR_CANONIZATION);


I've only ever used bind with one more argument than the bound function, not with two. Additionally,
uri.canonize
has this function signature:

void
FaceUri::canonize(const CanonizeSuccessCallback& onSuccess,
const CanonizeFailureCallback& onFailure,
boost::asio::io_service& io, const time::nanoseconds& timeout) const


And much further down the rabbit hole,
onSuccess
and
onFailure
do get called with one argument, but I don't think it's important to show all that here. Finally, the function signature for
onCanonizeSuccess
is:

void
FaceController::onCanonizeSuccess(const FaceUri& uri,
const CommandSuccessCallback& onSuccess,
const CommandFailureCallback& onFailure,
const FaceUri& request)


Really I'm just asking for someone to interpret this with me. Here's what I have understood:
uri.canonize
is being passed 4 arguments:


  1. A bound function, which is of the return type
    FaceController::onCanonizeSuccess
    , with the first arg bound to the
    uri
    object, the second arg passed to the bound function, then
    onSuccess
    ,
    onFailure
    , and
    uri
    .

  2. A bound function just like above, except the return type is
    FaceController::onCanonizeFailure
    .

  3. m_ioService

  4. TIME_ALLOWED_FOR_CANONIZATION



So what this means is that
FaceUri::canonize
here is being passed two function objects that each take 1 argument, and two other things. Then, when
FaceUri::canonize
ultimately calls its
onSuccess
with that one argument, since that function object is bound to a return type of
FaceController::onCanonizeSuccess
, that's the function that will be called.

That's my best attempt at understanding what's going on here. The only issue is that
FaceController::onCanonizeSuccess
isn't the bound function. It can't be, because the arity here means we're calling
bind
with a return type, and
this
is the function to bind to. What is
this
in this context? The top-most calling function?
uri
?
uri.canonize
? This is all as clear as mud. Unfortunately, I don't know which bind we're using, but I believe it is std::bind, since I see a using std::bind clause a few includes up.

Answer

So, void FaceUri::canonize is a function, which gets called. It accepts four arguments, being (with proper cv and ref qualifiers)
CanonizeSuccessCallback - a function, which gets called (guessing from the name, on success)
CanonizeFailureCallback - a function, which gets called (guessing from the name, on failure)
and two plain arguments, you probably understand.

Now, Canonize*Callback are probably objects (guessing templates), which supposes, to have proper operator() defined on them. I suppose you know the basics behind std::bind.

And uri.canonize is a function call, where first two arguments are functions, to be called when canonizing succeeds or fails.

According to onCanonizeSuccess singature, you have to pass four parameters to std::bind for that function. Well, actually, since that function is not static, it requires fifth (or rather null-th) argument of type FaceController* on which should the function (onCanonizeSuccess) be called.

bind(
  &FaceController::onCanonizeSuccess, // non-static member function requiring first argument to be pointer to FaceController instance
  this, // pointer to FaceController instance, that means, the object with function, where uri.canonize is called.
  _1, // actually std::placeholders::_1, meaning, that first argument will be passed when calling bound function                                                                                                             
  onSuccess, // rest of parameters
  onFailure,
  uri
)