Sign in to follow this  

[SOLUTION] boost bind and argument place holders

This topic is 3410 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

hey all, I'm trying something out with boost::bind but can't really get it to work (basically, im actually getting the errors I would have expected..) ok. So Im trying to create a function pointer with a "different" signature to the target function. By different I mean I want a default value specified for one of the parameters so that the callee doesnt only has to specify the other ones. so the following is what you would normally do, and it works as expected:
struct vec {
 float data[3];
 void set(int idx, float val) { data[idx] = val; }
 float get(int idx) const { return data[idx]; }
};

const int X_INDEX = 0, Y_INDEX = 1, Z_INDEX = 2;




vec v;
boost::function<void(int,float)> set = boost::bind( boost::mem_fn(&vec::set), &v, _1, _2 );

set(X_INDEX, 3.0f); /* set x! */



basically, what I would like to do is this:
boost::function<void(int,float)> setX = boost::bind( boost::mem_fn(&vec::set), &v, X_INDEX, _1 /* have tried _2 as well */ );

setX(3.0f); /* set x! */



I have tried jiggling the signature of function, but haven't had luck - compile errors (which I would post here, but I dont have a compiler atm...) so anyone know how I could do this? I'm reasonably experienced with boost, but I wouldn't say im anywhere near an expert. [Edited by - silvermace on August 12, 2008 5:29:35 AM]

Share this post


Link to post
Share on other sites
I've found a very very round-about way of working around this issue, but I'd still like for anyone to help out if they can?

for your information:
struct vec {
/* as before */
template<const int idx_> void set(float val) { data[idx_] = val; }
};




and bind as follows:
vec v;
boost::function<void(float)> setX = boost::bind(&vec::set< X_INDEX >, &v, _1);
boost::function<void(float)> setY = boost::bind(&vec::set< Y_INDEX >, &v, _1);
boost::function<void(float)> setZ = boost::bind(&vec::set< Z_INDEX >, &v, _1);
setX(3.0f); /* set x! */
setY(6.0f); /* set y! */
setZ(9.0f); /* set z! */


(not sure if that compiles, but see no reason why it wouldn't... will report back when I get it working..

Share this post


Link to post
Share on other sites
The following works for me:

static const int iui = 123;

struct E
{
int sum(int a, int b)
{
return a + b;
}
};

int main()
{
E e;
boost::function< int(int) > af = boost::bind(&E::sum, &e, iui, _2);
}


Notice that in the boost::function declaration, I'm dropping on of the parameters, as that's already specified in the boost bind. You should have boost::function< void (float) >

Share this post


Link to post
Share on other sites
Quote:
Original post by _goat
The following works for me:

*** Source Snippet Removed ***

Notice that in the boost::function declaration, I'm dropping on of the parameters, as that's already specified in the boost bind. You should have boost::function< void (float) >
hmm. what compiler are you using? also, your sample doesn't actually execute the function-obj? I hope that this in fact does work, and that I was simply sleepy and tired last night and made a mistake! thanks :)

Share this post


Link to post
Share on other sites
Quote:
Original post by silvermace
Quote:
Original post by _goat
The following works for me:

*** Source Snippet Removed ***

Notice that in the boost::function declaration, I'm dropping on of the parameters, as that's already specified in the boost bind. You should have boost::function< void (float) >
hmm. what compiler are you using? also, your sample doesn't actually execute the function-obj? I hope that this in fact does work, and that I was simply sleepy and tired last night and made a mistake! thanks :)


No, I never wrote the code to execute the object. I'm using MSVC8.

Share this post


Link to post
Share on other sites

boost::function<void(int,float)> setX = boost::bind( boost::mem_fn(&vec::set), &v, X_INDEX, _1 /* have tried _2 as well */ );

setX(3.0f); /* set x! */


You're binding the first int parameter. The boost::function object that you're creating is something you only want to pass a float to. setX should have type boost::function<void(float)> remove the first "int," argument, since the function object you're creating doesn't take 2 arguments

Share this post


Link to post
Share on other sites
yea, so, _goat that code sample which compiles for you under '08 refuses to compile for me under '05.

I can include the exact code I'm trying to compile and the error as well (now that I have my compiler!)

in TestCMLCompatible.hpp -- a header with inline class declaration which contains a bunch of unit tests

class TestCMLCompatibility : public TestSuite {
public:
/* ...other tests ...*/
void testBoostCompatible() {
cml::vector3f vec(1,2,3);
const int X_INDEX = 0;

boost::function<void(cml::vector3f::value_type)> setX = boost::bind( &cml::vector3f::set_element, &vec, X_INDEX,_2 );

setX(4.0f);

VET_ASSERT_TRUE(vec[0] == 4);
}
};




the exact error is as follows:

7>d:\dev\libraries\boost\boost_1_34_1\boost\bind.hpp(347) : error C2679: binary '[' : no operator found which takes a right-hand operand of type 'overloaded-function' (or there is no acceptable conversion)
7> d:\dev\libraries\boost\boost_1_34_1\boost\bind.hpp(205): could be 'float boost::_bi::list1<A1>::operator [](boost::arg<I>) const'
7> with
7> [
7> A1=float &,
7> I=1
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\bind.hpp(207): or 'float boost::_bi::list1<A1>::operator [](boost::arg<I> (__cdecl *)(void)) const'
7> with
7> [
7> A1=float &,
7> I=1
7> ]
7> while trying to match the argument list '(boost::_bi::list1<A1>, overloaded-function)'
7> with
7> [
7> A1=float &
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\bind\bind_template.hpp(32) : see reference to function template instantiation 'void boost::_bi::list3<A1,A2,A3>::operator ()<F,boost::_bi::list1<float &>>(boost::_bi::type<T>,F &,A &,int)' being compiled
7> with
7> [
7> A1=boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,
7> A2=boost::_bi::value<int>,
7> A3=boost::arg<2>,
7> F=boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,
7> T=void,
7> A=boost::_bi::list1<float &>
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\function\function_template.hpp(158) : see reference to function template instantiation 'void boost::_bi::bind_t<R,F,L>::operator ()<T0>(A1 &)' being compiled
7> with
7> [
7> R=void,
7> F=boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,
7> L=boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>,
7> T0=float,
7> A1=float
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\function\function_template.hpp(152) : while compiling class template member function 'void boost::detail::function::void_function_obj_invoker1<FunctionObj,R,T0>::invoke(boost::detail::function::function_buffer &,T0)'
7> with
7> [
7> FunctionObj=boost::_bi::bind_t<void,boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>>,
7> R=void,
7> T0=float
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\function\function_template.hpp(787) : see reference to class template instantiation 'boost::detail::function::void_function_obj_invoker1<FunctionObj,R,T0>' being compiled
7> with
7> [
7> FunctionObj=boost::_bi::bind_t<void,boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>>,
7> R=void,
7> T0=float
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\function\function_template.hpp(624) : see reference to function template instantiation 'void boost::function1<R,T0,Allocator>::assign_to<Functor>(const Functor &)' being compiled
7> with
7> [
7> R=void,
7> T0=float,
7> Allocator=std::allocator<void>,
7> Functor=boost::_bi::bind_t<void,boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>>
7> ]
7> d:\dev\libraries\boost\boost_1_34_1\boost\function\function_template.hpp(887) : see reference to function template instantiation 'boost::function1<R,T0,Allocator>::function1<boost::_bi::bind_t<R,F,L>>(Functor,int)' being compiled
7> with
7> [
7> R=void,
7> T0=float,
7> Allocator=std::allocator<void>,
7> F=boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,
7> L=boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>,
7> Functor=boost::_bi::bind_t<void,boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>>
7> ]
7> d:\dev\victoryengine\unit-test\src\test_cml_compatible.hpp(77) : see reference to function template instantiation 'boost::function<Signature>::function<boost::_bi::bind_t<R,F,L>>(Functor,int)' being compiled
7> with
7> [
7> Signature=void (float),
7> R=void,
7> F=boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,
7> L=boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>,
7> Functor=boost::_bi::bind_t<void,boost::_mfi::mf2<void,cml::vector<float,cml::fixed<3>>,size_t,float>,boost::_bi::list3<boost::_bi::value<cml::vector<float,cml::fixed<3>> *__w64 >,boost::_bi::value<int>,boost::arg<2>>>
7> ]




and cml::vector3f is a typedef: typedef vector< float, fixed<3> > vector3f; where value_type is typedef'ed to the template typename parameter which gets set to 'float'

any ideas?

VC++ 2005 SP1, Vista Business, Boost 1.34.1. Just going off to try compile with GCC 3.4 will post back

[Edit: cant get _goat's sample to compile on either compiler (VC05 or G++ 3.4.2 (mingw-special)...


D:/Dev/Libraries/boost/boost_1_34_1/boost/bind.hpp:337: error: invalid conversion from `boost::arg<2> (*)()' to `boost::arg<1> (*)()'
D:/Dev/Libraries/boost/boost_1_34_1/boost/bind.hpp:337: error: initializing argument 1 of `A1 boost::_bi::list1<A1>::operator[](boost::arg
<1> (*)()) const [with A1 = int&]'

]

Share this post


Link to post
Share on other sites
ok, solved it. Tried upgrading to boost 1.35.0, still got an error. but gave me a more interest error message - said that my arg<2> was returning a negative indicie. which made me think the template code unrolling wasnt stopping where it should have. so I replaced the _2 arg place holder with _1 and what do you know, it all worked...

I think I got a little confused really, I should have tried each combination and recorded a result somewhere to track. anyway, I have included the unit test (which passes) for completeness sake.

Also, I think the template<const int idx> solution is actually good enough if you're happy with that.


void testBoostCompatible() {
cml::vector3f vec(1,2,3);
const int X_INDEX = 0, Y_INDEX = 1, Z_INDEX = 2;

typedef boost::function<void(cml::vector3f::value_type)> setter_fn_t;

setter_fn_t setX = boost::bind( &cml::vector3f::set_element, &vec, X_INDEX, _1 );
setter_fn_t setY = boost::bind( &cml::vector3f::set_element, &vec, Y_INDEX, _1 );
setter_fn_t setZ = boost::bind( &cml::vector3f::set_element, &vec, Z_INDEX, _1 );

setX(4.0f);
setY(5.0f);
setZ(6.0f);

VET_ASSERT_TRUE(vec[0] == 4);
VET_ASSERT_TRUE(vec[1] == 5);
VET_ASSERT_TRUE(vec[2] == 6);
}




thanks for all that helped, Rate++

Share this post


Link to post
Share on other sites
in response to the op:

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

struct vec {
float data[3];
void set(int idx, float val) { data[idx] = val; }
float get(int idx) const { return data[idx]; }
};

const int X_INDEX = 0, Y_INDEX = 1, Z_INDEX = 2;


int main(){
vec v;
boost::function<void(int,float)> set = boost::bind( boost::mem_fn(&vec::set), &v, _1, _2 );
set(X_INDEX, 3.0f); /* set x! */
boost::function<void(float)> setX = boost::bind( &vec::set, &v, X_INDEX, _1 /* have tried _2 as well */ );
setX(4.0f); /* set x! */
}





this builds and executes as expected. your setX error is incorrect usage of boost::function. if you want your object to be passed one float and return nothing, your boost::function signature needs to be void(float). this is all explicitly documented in the very good online docs.

fwiw you seem to have spent nontrivial time figuring this out, whereas it took me about a minute without even my second cup of coffee. The lessons you should take away from this: Its almost never "someone else's bug". Reading and understanding the docs is time economical. "Jiggling" aka voodoo chicken coding is bad. Hopefully I only come off a little bit condescending here.

[Edited by - thedustbustr on August 12, 2008 9:07:56 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by sprite_hound
My version of cml doesn't seem to have a "set_element" vector method. Did you add it yourself?
yes, I modified CML vector/matrix base classes a bit to get it to play nice with Python. I also have created a few helper functions which might be of some use, I will pass them along to jyk to see what he thinks.

Share this post


Link to post
Share on other sites
Quote:
Original post by thedustbustr
fwiw you seem to have spent nontrivial time figuring this out, whereas it took me about a minute without even my second cup of coffee. The lessons you should take away from this: Its almost never "someone else's bug". Reading and understanding the docs is time economical. "Jiggling" aka voodoo chicken coding is bad. Hopefully I only come off a little bit condescending here.
Thanks for your help, but I never claimed it was "someone elses bug" if you read all my posts before posting, I always assumed that I was using bind wrong, which I was. Additionally, I found the problem by deduction, thanks to some positive help from _goat and RDragon1.

referring to my last post, see the part about confusion. The jiggling I refer to was only because I had somehow initially missed the correct usage actually compiling, which left me utterly confused.

Having said all that, I will keep in mind not to waste other people's time because I failed to test my code thoroughly, so to _goat and RDragon1, I apologise.

[And to show that my post isn't too diabolical, I have rate++ you because your advice, while not necessarily applicable to me, is good advice none the less.]

Share this post


Link to post
Share on other sites

This topic is 3410 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this