Mopparthy Ravindranath
Mopparthy Ravindranath

Reputation: 3308

boost::bind sending variable number of callback args to callback function

I am writing an asynchronous function that accepts a callback fn to invoke after completion. In general this works fine (but with some limitations) and I am able to send params as below.

#include <boost/bind.hpp>
#include <iostream>

void foo_cb(int result, const char* data) {
  std::cout << "foo_cb executed with params " << result << ", " << data << std::endl;
}


//void foo_caller(std::function<void(int, const char*)> ff) {
//template <typename... Args>
void foo_caller(std::function<void(int, const char*)> ff) {
  std::cout << "Caller executing..." << std::endl;
  ff(1, "hi");
}

int main(int argc, char** argv) {
  int x = 122;
  const char* y = "Hello nether world";
  foo_caller(boost::bind(foo_cb, x, y));
  return 0;
}

I have two issues here:

  1. Inside foo_caller() function, while invoking callback ff, I have to give some dummy values to satisfy the function signature of called fn i.e. ff(1, "hi"); But this executes correctly and prints the original values passed in main(). It looks very unnatural having to call ff() with some values, which won't be used.

  2. In my main(), I may decide to pass different types and/or numbers of arguments to the called-back function, and i write the the completion handler accordingly. In such case, how do I actually write the async function foo_caller(...) to take variable number of args and data types and correctly call the completion handler?

Update

Thanks to Jonesinator, after having looked at std::placeholders, I realized what mistake I was doing.

  1. foo_caller signature n definition were wrong.
  2. Invocation from main was also wrong.

The updated version of code that works is, below:

void foo_cb(int result, const char* data) {
  std::cout << "foo_cb executed with params " << result << ", " << data << std::endl;
}


void foo_caller(std::function<void(int, const char*)> ff, int a, const char* b) {
  std::cout << "Caller executing..." << std::endl;
  ff(a, b);
}


int main(int argc, char** argv) {

  int x = 122;
  const char* y = "Hello nether world";
  foo_caller(std::bind(foo_cb, std::placeholders::_1, std::placeholders::_2), x, y);
  return 0;
}

Upvotes: 2

Views: 341

Answers (2)

user3910497
user3910497

Reputation: 46

For your first issue: since you bind the arguments to the function, foo_caller's signature should be:

void foo_caller(std::function<void()> ff)

boost::bind copies the arguments you passed and creates a new callable entity that can be invoked with no arguments (since they're known by this new entity) and returns void.

When you want to pass arguments at a later time, you have to bind placeholders like Jonesinator explains in his answer.

Upvotes: 0

Jonesinator
Jonesinator

Reputation: 4216

Since you're using std::function you should probably also use std::bind. The std::bind function can take placeholder arguments for arguments that are not bound at the time the std::function is created.

Upvotes: 3

Related Questions