boost::bind and member functions

Hi, I'm interested in using boost::bind and std::transform to iterate through a container of member functions and initialize another container with the results. I've read through the documentation pretty carefully - in particular this bit from the bind documentation: typedef void (*pf)(int); std::vector<pf> v; std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5)); So I've been able to iterator through a set of *non* member functions and intialize another container with the results. When I try the code below, I get the following error message: boost/bind/apply.hpp:39: must use .* or ->* to call pointer-to-member function in `f (...)' I have tried several variations involving mem_fn to try and create the appropriate functors, but so far, no joy. Is there a known solution to accomplish what I want to do? Dave #include <vector> #include <iostream> #include <iterator> #include "boost/bind.hpp" #include "boost/bind/apply.hpp" using namespace std; using namespace boost; struct A { float a(int m, float x) { return m * x;} float b(int m, float x) { return m + x;} float c(int m, float x) { return m - x;} float d(int m, float x) { return m / x;} }; typedef float (A::*pfn)(int, float); int main() { A a; int m = 2; float x = 3.0; vector<pfn> v; vector<float> f; v.push_back(&A::a); v.push_back(&A::b); v.push_back(&A::c); v.push_back(&A::d); transform(v.begin(), v.end(), back_inserter(f), bind(apply<float>(), _1, a, m, x)); copy(f.begin(), f.end(), ostream_iterator<float>(cout, "\n")); }

Maybe not the best solution performance-wise, but you can try the following: Replace typedef float (A::*pfn)(int, float); with typedef boost::function3<float,A*,int,float> pfn; then v.push_back(&A::a); ... with v.push_back(boost::mem_fn(&A::a)); ... and finally transform( v.begin() , v.end() , back_inserter(f) , bind(apply<float>(), _1, a, m, x) ); with transform( v.begin() , v.end() , back_inserter(f) , bind(apply<float>(), _1, &a, m, x) ); I'm not sure if its necessary to include the extra header files, because bind might include them already, but you'll probably need: #include <boost/mem_fn.hpp> #include <boost/function.hpp> HTH Pablo Aguilar "David Morrison" <dave@bnl.gov> wrote in message news:42406A71.3030803@bnl.gov...
Hi,
I'm interested in using boost::bind and std::transform to iterate through a container of member functions and initialize another container with the results. I've read through the documentation pretty carefully - in particular this bit from the bind documentation:
typedef void (*pf)(int);
std::vector<pf> v;
std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));
So I've been able to iterator through a set of *non* member functions and intialize another container with the results. When I try the code below, I get the following error message:
boost/bind/apply.hpp:39: must use .* or ->* to call pointer-to-member function in `f (...)'
I have tried several variations involving mem_fn to try and create the appropriate functors, but so far, no joy. Is there a known solution to accomplish what I want to do?
Dave
#include <vector> #include <iostream> #include <iterator> #include "boost/bind.hpp" #include "boost/bind/apply.hpp"
using namespace std; using namespace boost;
struct A { float a(int m, float x) { return m * x;} float b(int m, float x) { return m + x;} float c(int m, float x) { return m - x;} float d(int m, float x) { return m / x;} };
typedef float (A::*pfn)(int, float);
int main() { A a; int m = 2; float x = 3.0;
vector<pfn> v; vector<float> f;
v.push_back(&A::a); v.push_back(&A::b); v.push_back(&A::c); v.push_back(&A::d);
transform(v.begin(), v.end(), back_inserter(f), bind(apply<float>(), _1, a, m, x));
copy(f.begin(), f.end(), ostream_iterator<float>(cout, "\n")); }

Pablo Aguilar wrote:
Maybe not the best solution performance-wise, but you can try the following:
Replace typedef float (A::*pfn)(int, float); with typedef boost::function3<float,A*,int,float> pfn;
Thanks, that works nicely, though the required coding difference is a bit disconcerting. I found that if I created a class in analogy with "apply" called, say, "apply_mem_fn" like this: namespace boost { template<class R> struct apply_mem_fn { typedef R result_type; template<class F, class A1, class A2, class A3> result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3) const { return ((a1).*(f))(a2, a3); } }; } // namespace boost Then I can achieve what I was trying to accomplish with code that looks nearly the same as in the case of pointers to non-member functions: #include <vector> #include <iostream> #include <iterator> #include "boost/bind.hpp" namespace boost { template<class R> struct apply_mem_fn { typedef R result_type; template<class F, class A1, class A2, class A3> result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3) const { return ((a1).*(f))(a2, a3); } }; } // namespace boost using namespace std; using namespace boost; struct A { float a(int m, float x) { return m * x;} float b(int m, float x) { return m + x;} float c(int m, float x) { return m - x;} float d(int m, float x) { return m / x;} }; typedef float (A::*pfn)(int, float); int main() { A a; int m = 2; float x = 3.0; vector<pfn> v; vector<float> f; v.push_back(&A::a); v.push_back(&A::b); v.push_back(&A::c); v.push_back(&A::d); transform(v.begin(), v.end(), back_inserter(f), bind(apply_mem_fn<float>(), _1, a, m, x)); copy(f.begin(), f.end(), ostream_iterator<float>(cout, "\n")); } It's not clear to me whether it's possible to choose the right implementation based on the argument. Dave

David Morrison wrote:
I found that if I created a class in analogy with "apply" called, say, "apply_mem_fn" like this:
template<class R> struct apply_mem_fn { typedef R result_type;
template<class F, class A1, class A2, class A3> result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3) const { return ((a1).*(f))(a2, a3);
Change this to boost::mem_fn( f )( a1, a2, a3 ) and you'll be there.
}
};

Peter Dimov wrote:
Change this to boost::mem_fn( f )( a1, a2, a3 ) and you'll be there.
Yep, that's much cleaner, thanks. I was hoping that there'd be some clever way to use type_traits to magically select the right way of invoking the function f. That way, one could have a (possibly enhanced version of?) apply.hpp so that code to invoke apply on a set of member and non-member functions would look the same. Gives me an excuse to dig into traits, I suppose. Dave

David Morrison wrote:
Peter Dimov wrote:
Change this to boost::mem_fn( f )( a1, a2, a3 ) and you'll be there.
Yep, that's much cleaner, thanks.
I was hoping that there'd be some clever way to use type_traits to magically select the right way of invoking the function f. That way, one could have a (possibly enhanced version of?) apply.hpp so that code to invoke apply on a set of member and non-member functions would look the same.
On a reasonably conforming compiler, adding an overload to apply<> should work: template<class F, class A1, class A2, class A3> result_type operator() (F & f, A1 & a1, A2 & a2, A3 & a3) const { return f(a1, a2, a3); } // add this template<class M, class T, class A1, class A2, class A3> result_type operator() (M T::* pm, A1 & a1, A2 & a2, A3 & a3) const { return mem_fn(pm)(a1, a2, a3); } It might be a good idea to add this to apply.hpp, but I would need to write a test for apply<> first.

Peter Dimov wrote:
David Morrison wrote:
Peter Dimov wrote:
Change this to boost::mem_fn( f )( a1, a2, a3 ) and you'll be there.
Yep, that's much cleaner, thanks.
I was hoping that there'd be some clever way to use type_traits to magically select the right way of invoking the function f. That way, one could have a (possibly enhanced version of?) apply.hpp so that code to invoke apply on a set of member and non-member functions would look the same.
On a reasonably conforming compiler, adding an overload to apply<> should work:
template<class F, class A1, class A2, class A3> result_type operator() (F & f, A1 & a1, A2 & a2, A3 & a3) const { return f(a1, a2, a3); }
// add this
template<class M, class T, class A1, class A2, class A3> result_type operator() (M T::* pm, A1 & a1, A2 & a2, A3 & a3) const { return mem_fn(pm)(a1, a2, a3); }
It might be a good idea to add this to apply.hpp, but I would need to write a test for apply<> first. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
-- David Morrison Brookhaven National Laboratory phone: 631-344-5840 Physics Department, Bldg 510 C fax: 631-344-3253 Upton, NY 11973-5000 email: dave@bnl.gov

Peter Dimov wrote:
On a reasonably conforming compiler, adding an overload to apply<> should work:
template<class F, class A1, class A2, class A3> result_type operator() (F & f, A1 & a1, A2 & a2, A3 & a3) const { return f(a1, a2, a3); }
// add this
template<class M, class T, class A1, class A2, class A3> result_type operator() (M T::* pm, A1 & a1, A2 & a2, A3 & a3) const { return mem_fn(pm)(a1, a2, a3); }
It might be a good idea to add this to apply.hpp, but I would need to write a test for apply<> first.
Sorry for the incomplete previous post. What I meant to say was ... That looks very interesting. And if I augment my previous code with your suggestion I get the result below. Except for the obvious (and expected) difference of needing to pass an instance of the class in question, the member function and non-member function uses of apply look identical. Very nice. Dave #include <vector> #include <iostream> #include <iterator> #include "boost/bind.hpp" namespace boost { template<class R> struct apply { typedef R result_type; template<class M, class T, class A1, class A2, class A3> result_type operator() (M T::* pm, A1 & a1, A2 & a2, A3 & a3) const { return mem_fn(pm)(a1, a2, a3); } template<class F, class A1, class A2, class A3> result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3) const { return boost::mem_fn(f)(a1, a2, a3); } template<class F, class A1, class A2> result_type operator()(F & f, A1 & a1, A2 & a2) const { return f(a1, a2); } }; } // namespace boost using namespace std; using namespace boost; struct A { float a(int m, float x) { return m * x;} float b(int m, float x) { return m + x;} float c(int m, float x) { return m - x;} float d(int m, float x) { return m / x;} }; float a2(int m, float x) { return m * x;} float b2(int m, float x) { return m + x;} float c2(int m, float x) { return m - x;} float d2(int m, float x) { return m / x;} typedef float (A::*pfn)(int, float); typedef float (*pfn2)(int, float); int main() { A a; int m = 2; float x = 3.0; vector<pfn> v; vector<pfn2> v2; vector<float> f; v.push_back(&A::a); v.push_back(&A::b); v.push_back(&A::c); v.push_back(&A::d); v2.push_back(&a2); v2.push_back(&b2); v2.push_back(&c2); v2.push_back(&d2); transform(v.begin(), v.end(), back_inserter(f), bind(apply<float>(), _1, a, m, x)); transform(v2.begin(), v2.end(), back_inserter(f), bind(apply<float>(), _1, m, x)); copy(f.begin(), f.end(), ostream_iterator<float>(cout, "\n")); }
participants (3)
-
David Morrison
-
Pablo Aguilar
-
Peter Dimov