4

I am using a class that needs some kind of callback method, so i'm using boost::function to store the function pointers.

i need the callback to have one optional argument, but i found out that boost::function won't let me define optional arguments kind of type, so i tried the following code and it worked..

//the second argument is optional  
typedef boost::function< int (int, char*)> myHandler;  

class A   
{  
public:  
     //handler with 2 arguments  
     int foo(int x,char* a) {printf("%s\n",a);   return 0;}; 
     //handler with 1 argument
     int boo(int x) {return 1;};       
}

A* a = new A;  
myHandler fooHandler= boost::bind(&A::foo,a,_1,_2);  
myHandler booHandler= boost::bind(&A::boo,a,_1);    

char* anyCharPtr = "just for demo";  
//This works as expected calling a->foo(5,anyCharPtr)  
fooHandler(5,anyCharPtr);  
//Surprise, this also works as expected, calling a->boo(5) and ignores anyCharPtr 
booHandler(5,anyCharPtr);   

I was shocked that it worked, question is should it work, and is it legit?
is there a better solution?

Gaby Rubin
  • 53
  • 4
  • 1
    IMO what is strange here is not where your `//surprise` is, but that you can declare `booHandler` as of `myHandler` type. – Benoit Mar 04 '11 at 10:55
  • and if only fooHandler would fail too for binding a literal to char * – CashCow Mar 04 '11 at 11:10

1 Answers1

3

Arguably a type safety hole in the bind -> function conversion. boost::bind doesn't return an std::function but a function object of a very complicated type. In the case of

boost::bind(&A::boo,a,_1);

as seen above, the returned object has type

boost::_bi::bind_t<
  int, 
  boost::_mfi::mf1<int,A,int>,
  boost::_bi::list2<boost::_bi::value<A*>, boost::arg<1> > 
>

std::function only checks that the supplied function object is "compatible", in this case, whether it is callable with an int as the first argument and a pointer to char as the second argument. Upon examining the *boost::bind_t* template, we see that it does indeed have a matching function call operator:

template<class A1, class A2> result_type operator()(A1 & a1, A2 & a2)

Inside this function the second argument ends up being silently discarded. This is by design. From the documentation: Any extra arguments are silently ignored (...)

decltype
  • 1,591
  • 8
  • 12