How can I make boost :: function not so soft?

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 a way that I can make the second call to RegisterCallback uncompiled?

In the context:
I recently changed the callback signature and added the bool argument. I thought I updated everything I used this, but I was wrong. Besides renaming RegisterCallback every time I change the signature, I would like to have a way to force the compiler to use all arguments.

+4
source share
4 answers

I was a bit late with this answer, but since the problem is that you could take this step later using the template version for your callback registration function, and the other 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 lacks the need for not one, but two callback registration functions to work correctly with member functions and non-members.

As another option, you can look at the boost_types library. It provides the metafunction parameter_types, which retrieves the parameter types of function pointers and returns them as an MPL sequence. Then, using the matte magic of the template, you can check the parameters of the callback function, for example:

 #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 you can pack them into one if you define them inside the structure (and use the default template parameter argument for T);

0
source

The documentation states

Any additional arguments are silently ignored.

This should be such as 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 at the beginning, at the end or in the middle of the argument list can be ignored.

You will need a simpler binder that does not support anything like _N placeholders. Boost doesn't seem to have this.

+2
source

The problem is not boost::function ; the problem is that the boost::bind object returned by the function will accept something as parameters. Bind is more or less specified runtime, not compilation time. Therefore, the boost::bind object can be used with any boost::function .

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

+1
source

Instead, you can use std::function<...> .

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; } 
+1
source

All Articles