4
typedef boost::function<void (int,bool)> MyCallback;
void RegisterCallback(MyCallback callback);

class A {
public:
    void GoodCallback(int intArg,bool boolArg) {
        printf("calling GoodCallback (%d,%s)\n",intArg,boolArg?"true":"false");
    }

    void BadCallback(int intArg) {
        printf("calling BadCallback (%d)\n",intArg);
    }
};

int TestFunction() {
    A * myA=new A();
    RegisterCallback(boost::bind(&A::GoodCallback,myA,_1,_2));

    RegisterCallback(boost::bind(&A::BadCallback,myA,_1));

    return 0;
}

Is there any way that I can make the second call to RegisterCallback not compile?

For context:
I recently changed the callback signature and added the bool argument. I thought I had updated everything that was using this, but I was mistaken. Other than renaming RegisterCallback everytime I change the signature, I would like to have a way to have the compiler enforce that all arguments are used.

IronMensan
  • 6,761
  • 1
  • 26
  • 35

4 Answers4

2

The documentation says

Any extra arguments are silently ignored

It has to be this way in order to support _N placeholders. Witness:

void foo (int a, const char* b) {
  std::cout << "called foo(" << a << "," << b << ")" << std::endl;
}

int main () {
  boost::bind(foo,_1, _2)(1, "abc", foo, main, 2.0);
  boost::bind(foo,_2, _5)(3.0, 2, foo, main, "def");
}

prints

called foo(1,abc)
called foo(2,def)

Any combination of arguments in the beginning, in the end or in the middle of the argument list can be ignored.

You need a simpler binder that doesn't support anything like _N placeholders. Boost doesn't seem to have one.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
1

The problem isn't boost::function; the problem is that the function object boost::bind returns will take anything as parameters. Bind is, more or less, runtime defined, not compile-time defined. Therefore, the boost::bind object can be used with any boost::function.

[edit] OK, apparently boost::function is also a problem. But it's not the only problem.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
1

You could always use std::function<...> instead.

The following does not compile on VS2010 SP1:

#include <functional>

void foo();
void bar(int);

int main()
{
    std::function<void ()> f= std::bind(foo);
    std::function<void ()> g= std::bind(bar); // does not match signature, does not compile.
    return 0;
}
MSN
  • 53,214
  • 7
  • 75
  • 105
0

I'm a bit late with this answer but since the problem is the binding you could do this step later with the help of a templated version for your callback registration function and another one for regular function pointers:

template<typename C>
void RegisterCallback(void (C::* func)(int, bool), C* inst)
{
  MyCallback callback(boost::bind(func, inst, _1,_2));
}

void RegisterCallback(void (*func)(int, bool))
{
  MyCallback callback(func);
}

A * myA = new A();     
RegisterCallback(&A::GoodCallback, myA);      
RegisterCallback(&A::BadCallback, myA); // DOES NOT COMPILE

RegisterCallback(GoodCallback);
RegisterCallback(BadCallback); // DOES NOT COMPILE

This works as expected in VS2010 but has the disavantage of needing not one but two callback registration functions to correctly deal with member and non-member functions.

As another option you might have a look at the boost function_types library. It provides a parameter_types metafunction that extracts the parameter types of function pointers and returns them as a MPL sequence. Then with a bit template magic it's possible to validate the parameters of the callback function, something like:

#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/mpl/equal.hpp>

using namespace boost;
using namespace boost::function_types;

template< typename Function >
void RegisterCallback(Function f)
{
   BOOST_MPL_ASSERT(( 
      mpl::equal< 
        parameter_types< Function >, 
        parameter_types< void(int,bool) >
      > 
   ));

   MyCallback callback(f);
}

template<typename Function, typename T>
void RegisterCallback(Function f, T* inst)
{
   BOOST_MPL_ASSERT(( 
     mpl::equal< 
       parameter_types< Function >, 
       parameter_types< void (T::*)(int,bool) >
     > 
   ));

   MyCallback callback(boost::bind(f, inst, _1, _2));  
}

This also works as expected in VS2010 but you still need two function declarations although it should be possible to pack them in one if you define them inside a struct (and use a default template parameter argument for T);

floyd73
  • 1,240
  • 9
  • 12
  • There needs to be three registration functions `void RegisterCallback(void (C::* func)(int, bool) const, const C* inst)` – IronMensan Aug 01 '11 at 13:56
  • Yes, you're right, this is the disavantage of using function overloads for registering the callback - you'll need to provide overloads for every const/non-const member/non-member volatile/non-volatile etc. combination of signatures to handle general cases and the number of overloads grows exponentialy with the parameter count. For this reason I would be more inclined to use the function_types libraries to validate the function pointer since this is exactly the kind of problem that the library attempts to solve. – floyd73 Aug 02 '11 at 06:49