Search code examples
c++functionboost-bindstdbind

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.


Solution

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