yano
yano

Reputation: 5265

How to call a boost::function object with all arguments bound

I've been reading up on boost::function and boost::bind, however, I can't seem to figure out a "good way" to call a boost function if all the arguments are bound (I think that's the right terminology). Below is an untested MCVE (copying-and-pasting my real code is not ideal).

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

void func(void* args)
{
  int* myInt = static_cast<int*>(args);
  if (myInt != NULL)
  {
    std::cout << "myInt = " << *myInt << std::endl;
  }
  else
  {
    std::cout << "args is NULL" << std::endl;
  }
}

int main()
{
  int myInt1 = 5;
  int myInt2 = 45;

  boost::function<void(void* args)> myFunc = boost::bind(&func, &myInt1);

  // here's my problem,, how do I call myFunc?
  myFunc();  // this does not compile due to missing arguments
  myFunc;    // this is essentially a no-op. The function doesn't execute,
             // and if I put a breakpoint here, it either goes to the next
             // line or I get a warning that no executable code exists here

  // after some experimentation, I realized I can do this and it works
  myFunc(NULL);  // this prints out "myInt = 5"

  // this also prints out "myInt = 5"
  boost::bind(&func, &myInt1)();

  // finally, this prints out "myInt = 5" as well
  myFunc(&myInt2);

  return 0;
}

So my question is, what's the preferred/right way to call myFunc? I've successfully called functions with the _1, _2, etc argument placeholders by passing in the appropriate arguments.. maybe in practice there are placeholders almost all the time? myFunc(NULL) works, but it seems silly to me that I must essentially make up arguments if I've already bound them (and what I pass in doesn't matter anyway). In my real code, I actually want to call myFunc in a different function (so boost::bind(&func, &myInt1)(); isn't an option), and I'm doing so inside an object of a class, so I hope the example I've provided exhibits identical behavior to what I'm seeing in my real code. I'm using Visual Studio 2013, and c++11 or later cannot be used.

Upvotes: 2

Views: 1096

Answers (2)

aschepler
aschepler

Reputation: 72271

A better type for your myFunc variable would be boost::function<void()>, because with all arguments of the original func bound, no arguments are really needed to call the resulting wrapper.

boost::function<void()> myFunc = boost::bind(&func, &myInt1);

This would in fact allow you to call the function with just:

myFunc();

But the reason the compiler allowed the boost::function<void(void*)> type there is that the result of a boost::bind call can be called with more arguments than necessary if you choose to, and extra arguments are just ignored. One thing this does is makes situations like this a bit more consistent:

void f(int, int);
// g1 acts the same as f:
boost::function<void(int, int)> g1 = boost::bind(f, _1, _2);
// g2 swaps the order of arguments when calling f:
boost::function<void(int, int)> g2 = boost::bind(f, _2, _1);
// g3 ignores its first argument and passes the second to f twice:
boost::function<void(int, int)> g3 = boost::bind(f, _2, _2);
// g4 ignores its second argument and passes the first to f twice:
boost::function<void(int, int)> g4 = boost::bind(f, _1, _1);

In the g4 initialization, we can say the bind expression is just another bound function that can be called with exactly two int arguments, because it doesn't use any placeholders with position larger than 2. It can also be called with just one argument since _2 itself isn't ever used either, but that doesn't make the above false.

So similarly, in your code initializing boost::function<void(void*)>, the compiler accepts the completely bound bind expression as something which can validly be called with one argument, since it doesn't use any placeholders with position larger than 1. Though since in fact it doesn't use the placeholder _1 with position exactly 1 either, the void* input when used in that way just ends up being ignored.

Upvotes: 2

juanchopanza
juanchopanza

Reputation: 227390

A function object with "all parameters bound" has no parameters, so its type would be boost::function<void()>. You need

boost::function<void()> myFunc = boost::bind(&func, &myInt1);

Upvotes: 5

Related Questions