
Hello, A few days ago I developed a function argument caster because of a situation I had. Imagine you had a callback function that takes 4 arguments. x,y position of your mouse pointer, a bool indicating if a button is pressed, and then an int indicating the button that is pressed. Now imagine you already have a function that takes 2 ints representing the mouse coordinates and then renders an image at those coordinates. You can't assign this function to the callback because the sigs don't match. So you have a couple of options. a) wrap the function in a struct and overload operator () b) change the signature (but then change all places where you've invoked the function already) A produced unnecessary clutter and B can be error-prone depending on how big the project is. So I propose a function argument caster: bool drawfunc(int, int); callback = args_cast< 2, bool(int,int,bool,int) >(&drawfunc); callback( x, y, true, 3 ); // calls drawfunc(x,y) NOTE: the '2' as the first template parameter tells args_cast how many arguments the original function takes. The implementation I have also allows you to rewire the arguments from the synthsized function to the actual arguments, eg: callback = args_cast< 2, bool(int,int,bool,int), 1, 4 >(&drawfunc); callback( x, y, true, 3 ); // calls drawfunc(x,3) What do you guys think? If anyone is interested I posted the code to a game development community a while back. http://www.devmaster.net/forums/showthread.php?t=7744 - ali

On 12/7/06, ali f <k9eks@hotmail.com> wrote:
a) wrap the function in a struct and overload operator () b) change the signature (but then change all places where you've invoked the function already)
c) Use Boost.Bind.
From http://boost.org/libs/bind/bind.html#with_functions : bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x) Note that, in the last example, the function object produced by bind(g, _1, _1, _1) does not contain references to any arguments beyond the first, but it can still be used with more than one argument. Any extra arguments are silently ignored, just like the first and the second argument are ignored in the third example.

Boost.Bind can indeed be used to decrease the number of args a function can take, but it can't be used to increase the number of args a function can take. In the example I gave in my original post, the callback: bool callback(int,int,bool,int); and you have a functon bool draw(int,int) You can't use bind to assign "draw" to "callback". args_cast can be used though. - ali ----- Original Message ----- From: "me22" <me22.ca@gmail.com> Newsgroups: gmane.comp.lib.boost.devel Sent: Friday, December 08, 2006 6:30 PM Subject: Re: new utility: function parameter caster
On 12/7/06, ali f <k9eks@hotmail.com> wrote:
a) wrap the function in a struct and overload operator () b) change the signature (but then change all places where you've invoked the function already)
c) Use Boost.Bind.
From http://boost.org/libs/bind/bind.html#with_functions : bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x) Note that, in the last example, the function object produced by bind(g, _1, _1, _1) does not contain references to any arguments beyond the first, but it can still be used with more than one argument. Any extra arguments are silently ignored, just like the first and the second argument are ignored in the third example.
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Peter: I tried #include <boost/bind.hpp> void draw(int, int) {} int main() { boost::bind<void>(&draw, _1, _2) (1, 2, 3, 4); return 0; } and that didn't compile. How did you mean this: "Yes it can"? -- Hervé Brönnimann hervebronnimann@mac.com On Dec 9, 2006, at 9:24 AM, Peter Dimov wrote:
ali f wrote:
Boost.Bind can indeed be used to decrease the number of args a function can take, but it can't be used to increase the number of args a function can take.
Yes it can. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

Hervé Brönnimann wrote:
Peter: I tried
#include <boost/bind.hpp> void draw(int, int) {}
int main() { boost::bind<void>(&draw, _1, _2) (1, 2, 3, 4); return 0; }
and that didn't compile. How did you mean this: "Yes it can"?
Try one of 1. Using the above with CVS HEAD (you don't need the <void> and the &, but with works with them); 2. Passing lvalues: int main() { int a1 = 1, a2 = 2, a3 = 3, a4 = 4; boost::bind<void>(&draw, _1, _2) (a1, a2, a3, a4); } 3. A real scenario: int main() { boost::function< void( int, int, int, int ) > callback = boost::bind( draw, _1, _2 ); callback( 1, 2, 3, 4 ); }

wow, that actually works! did not know that. never mind the args_cast then i guess :) sorry for wasting time. - ali

Indeed, I tried and to my surprise it doesn't work (both boost::bind (&draw, _1, _2)(1,2,3,4) and boost::bind<void>(&draw, _1, _2)(1,2,3,4)). But there is no reason (other than design) it couldn't. In fact, our company's version of bind (I mean at Bloomberg LP) *does* allow extra arguments to be passed to a non-explicit binder (i.e. one whose signature cannot be determined from the bound object at binding time). The extra unused arguments are simply dropped. Now I could imagine that the authors of boost.bind do *not* want to allow this for type safety reasons, i.e. matching the signature exactly. That would be understandable. In that case I'd say you have a point. -- Hervé Brönnimann hervebronnimann@mac.com On Dec 8, 2006, at 5:37 AM, ali f wrote:
Boost.Bind can indeed be used to decrease the number of args a function can take, but it can't be used to increase the number of args a function can take. In the example I gave in my original post, the callback:
bool callback(int,int,bool,int);
and you have a functon
bool draw(int,int)
You can't use bind to assign "draw" to "callback". args_cast can be used though.
- ali
----- Original Message ----- From: "me22" <me22.ca@gmail.com> Newsgroups: gmane.comp.lib.boost.devel Sent: Friday, December 08, 2006 6:30 PM Subject: Re: new utility: function parameter caster
On 12/7/06, ali f <k9eks@hotmail.com> wrote:
a) wrap the function in a struct and overload operator () b) change the signature (but then change all places where you've invoked the function already)
c) Use Boost.Bind.
From http://boost.org/libs/bind/bind.html#with_functions : bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x) Note that, in the last example, the function object produced by bind(g, _1, _1, _1) does not contain references to any arguments beyond the first, but it can still be used with more than one argument. Any extra arguments are silently ignored, just like the first and the second argument are ignored in the third example.
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost

Hervé Brönnimann wrote:
Indeed, I tried and to my surprise it doesn't work (both boost::bind (&draw, _1, _2)(1,2,3,4) and boost::bind<void>(&draw, _1, _2)(1,2,3,4)).
Calling bind with (1, 2, 3, 4) doesn't work for you because of the rvalues. It works with the latest CVS HEAD. You don't even need the & in front of draw. boost::bind has been allowing extra arguments since day one.

Hi again, ok, here's my actual real world situation: win->on_mouse_move.connect( args_cast<2, bool(int,int,bool,int)>( ( lambda::var(x) = lambda::_1, lambda::var(y) = lambda::_2, true ) ) ); on_mouse_move is a boost.signal. I want to use lambda because it's a simple thing to do. I just want to change some local variables according to where the mouse moves in my window. on_mouse_move is called everytime there's a mouse move (duh). So anyway, I can do the above with args_cast, I can't get it working with bind: win->on_mouse_move.connect( boost::bind( ( lambda::var(x) = lambda::_1, lambda::var(y) = lambda::_2, true ), _1, _2 ) ); I tried it with a templated function object call, ie the following works template< class F > void call( F f ) { int a = 1, b = 2, c = 3, d = 4; //f( 1, 2, 3, 4 ); f(a, b, c, d); } call( boost::bind( &draw, _1, _2 ) ); But it seems like it doesn't make sence or something... ----- Original Message ----- From: "Peter Dimov" <pdimov@mmltd.net> Newsgroups: gmane.comp.lib.boost.devel Sent: Saturday, December 09, 2006 5:44 PM Subject: Re: new utility: function parameter caster Hervé Brönnimann wrote:
Indeed, I tried and to my surprise it doesn't work (both boost::bind (&draw, _1, _2)(1,2,3,4) and boost::bind<void>(&draw, _1, _2)(1,2,3,4)).
Calling bind with (1, 2, 3, 4) doesn't work for you because of the rvalues. It works with the latest CVS HEAD. You don't even need the & in front of draw. boost::bind has been allowing extra arguments since day one. _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

ali f wrote:
Hi again,
ok, here's my actual real world situation:
win->on_mouse_move.connect( args_cast<2, bool(int,int,bool,int)>( ( lambda::var(x) = lambda::_1, lambda::var(y) = lambda::_2, true ) ) );
The following: win->on_mouse_move.connect( ( lambda::var(x) = lambda::_1, lambda::var(y) = lambda::_2, lambda::_4, true ) ); would be Lambda's way to make it accept four arguments and only use the first two; it doesn't subscribe to boost::bind's philosophy of automatically ignoring extra arguments. Unfortunately, Lambda doesn't have _4, which makes the suggested workaround a bit limited. :-) Your attempt at using boost::bind with it didn't work probably because you didn't specify a return type. Try boost::bind<bool>.

Thanks! In my haste to test, I forgot about the lvalue problem, of course. Been bitten by this one enough times, though :-) -- Hervé Brönnimann hervebronnimann@mac.com On Dec 9, 2006, at 9:44 AM, Peter Dimov wrote:
Hervé Brönnimann wrote:
Indeed, I tried and to my surprise it doesn't work (both boost::bind (&draw, _1, _2)(1,2,3,4) and boost::bind<void>(&draw, _1, _2)(1,2,3,4)).
Calling bind with (1, 2, 3, 4) doesn't work for you because of the rvalues. It works with the latest CVS HEAD. You don't even need the & in front of draw. boost::bind has been allowing extra arguments since day one.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/ listinfo.cgi/boost
participants (4)
-
ali f
-
Hervé Brönnimann
-
me22
-
Peter Dimov