using lambda's pointer to member function and boost::function

Hi, I'm trying to put a simple lambda functor which uses pointer to member function into a boost::function like this: struct aux { int a() const { return 5; } }; int main() { function<int(const aux &)> f = &_1->*&aux::a; } But the compiler chokes at the assignment with the error: /usr/include/boost/function/function_template.hpp:119: error: cannot convert 'boost::lambda::detail::member_pointer_caller<int, const aux*, int (aux::*)()const>' to 'int' in return I think it should be able to convert the member_pointer_caller to boost::function, as its result (int) is the same of function's result, as well as its only argument is the one that makes the lambda functor valid. According to the documentation, something like this should work because it says that boost::function<int(int, int)> f = _1 + _2 works. Am I missing something? Thank you, Rodolfo Lima.

rodolfo@rodsoft.org wrote:
Hi, I'm trying to put a simple lambda functor which uses pointer to member function into a boost::function like this:
struct aux { int a() const { return 5; } };
int main() { function<int(const aux &)> f = &_1->*&aux::a; }
But the compiler chokes at the assignment with the error:
/usr/include/boost/function/function_template.hpp:119: error: cannot convert 'boost::lambda::detail::member_pointer_caller<int, const aux*, int (aux::*)()const>' to 'int' in return
Try function<int(const aux &)> f = (&_1->*&aux::a)(); or function<int(const aux &)> f = bind( &aux::a, _1 ); or function<int(const aux &)> f = &aux::a;

function<int(const aux &)> f = (&_1->*&aux::a)();
This doesn't work because you are evaluating the functor without arguments, whereas it requires one.
function<int(const aux &)> f = bind( &aux::a, _1 );
This would work, but I in my project I have to call operator->* because in my case aux is a class that models a pointer, but doesn't have a dereference operator, just operator->* and operator->, those are the only ways to access the containing pointer. Well, there's also a ptr member function that returns it, but I'm trying to achieve the most natural way to access the containing pointer members. By using aux's ptr member, I have to use bind functions, which is a little unnatural.
or
function<int(const aux &)> f = &aux::a;
That doesn't make it either because f(a) just would return a delayed call to &aux::a, not its actual result. By trying to correct your first example, I've come with: function<int(const aux &)> f = (&protect(_1)->*&aux::a)(); The rationale is that the first evaluation without parameter would return a functor that expects an aux object, and would return aux::a return value (int), but this also fails compiling because class other_action<member_pointer_action>::apply fails to conclude that &protect(_1) is actually a pointer, and so it calls member_pointer_action_helper<false, false>::apply, which is the wrong choice. IMO the right choice would be member_pointer_action_helper<false, true> which evaluates the pointer to member function. Thanks for your help, Rodolfo Lima.

Rodolfo Lima wrote:
function<int(const aux &)> f = (&_1->*&aux::a)();
This doesn't work because you are evaluating the functor without arguments, whereas it requires one.
You are right, it doesn't work; lambda's operator->* seems a pretty odd beast. Interesting that nobody has discovered its quirks so far. FWIW, the syntax above is how it should work in order to be usable. Lambda currently implements aux x; (&_1->*&aux::a)( x )(); instead of (&_1->*&aux::a)()( x ); The current functionality doesn't make much sense to me; if you had x at the time the lambda expression is constructed, you could have used it directly and skip the _1 business.
function<int(const aux &)> f = bind( &aux::a, _1 );
This would work, but I in my project I have to call operator->* because in my case aux is a class that models a pointer, but doesn't have a dereference operator, just operator->* and operator->, those are the only ways to access the containing pointer. Well, there's also a ptr member function that returns it, but I'm trying to achieve the most natural way to access the containing pointer members. By using aux's ptr member, I have to use bind functions, which is a little unnatural.
You can use the above syntax with boost::bind and overload get_pointer for aux, but this won't work for lambda::bind or std::tr1::bind. Can't you just add operator* to aux? A raw pointer can escape via ptr, so adding a way to dereference the pointer doesn't seem to make it any more dangerous.
or
function<int(const aux &)> f = &aux::a;
That doesn't make it either because f(a) just would return a delayed call to &aux::a, not its actual result.
It works for your example and returns 5. When I add an aux_ptr class with a get_pointer overload,
function<int(const aux_ptr &)> f = &aux::a;
works through it, too.

You are right, it doesn't work; lambda's operator->* seems a pretty odd beast. Interesting that nobody has discovered its quirks so far. FWIW, the syntax above is how it should work in order to be usable. Lambda currently implements
That's how I thought it would work. Is it difficult to make lambda work this way?
You can use the above syntax with boost::bind and overload get_pointer for aux, but this won't work for lambda::bind or std::tr1::bind. Can't you just add operator* to aux? A raw pointer can escape via ptr, so adding a way to dereference the pointer doesn't seem to make it any more dangerous.
No, I can't add operator* to aux because its ptr member function actually returns a shared_ptr that it gets from another source. If this source doesn't own the shared_ptr, ptr will return a shared_ptr with use_count 1. If we define this member as T &operator*() { return *ptr(); } it would return a reference to an object that is already deleted by ~shared_ptr. By using only ->* or -> returning a shared_ptr, it will last until the end of the member function call.
It works for your example and returns 5. When I add an aux_ptr class with a
My example doesn't compile with g++ 4.1.1, which compiler are you using?
function<int(const aux_ptr &)> f = &aux::a;
works through it, too.
What if aux::a has a parameter? I'd like to do: function<int(const aux &)> f = (&_1->*&aux::a)(x,y,z); Thanks, Rodolfo Lima.

Rodolfo Lima wrote:
You are right, it doesn't work; lambda's operator->* seems a pretty odd beast. Interesting that nobody has discovered its quirks so far. FWIW, the syntax above is how it should work in order to be usable. Lambda currently implements
That's how I thought it would work. Is it difficult to make lambda work this way?
No idea. :-)
You can use the above syntax with boost::bind and overload get_pointer for aux, but this won't work for lambda::bind or std::tr1::bind. Can't you just add operator* to aux? A raw pointer can escape via ptr, so adding a way to dereference the pointer doesn't seem to make it any more dangerous.
No, I can't add operator* to aux because its ptr member function actually returns a shared_ptr that it gets from another source. If this source doesn't own the shared_ptr, ptr will return a shared_ptr with use_count 1. If we define this member as
T &operator*() { return *ptr(); }
it would return a reference to an object that is already deleted by ~shared_ptr. By using only ->* or -> returning a shared_ptr, it will last until the end of the member function call.
I see... then a get_pointer overload won't work either, since you can't return a raw pointer from it, and shared_ptr doesn't define operator->*. If you can't cache the shared_ptr locally in aux, the only remaining option is two nested binds.
It works for your example and returns 5. When I add an aux_ptr class with a
My example doesn't compile with g++ 4.1.1, which compiler are you using?
I happened to use VC 8.0 for the below. But this is just a variation of the example you posted; I didn't know about the shared_ptr trickery yet. #include <boost/function.hpp> #include <iostream> struct aux { int a() const { return 5; } }; struct aux_ptr { aux * px_; }; aux * get_pointer( aux_ptr const & p ) { return p.px_; } int main() { boost::function<int(const aux_ptr &)> f = &aux::a; aux x; aux_ptr px = { &x }; std::cout << f( px ) << std::endl; }

No idea. :-)
Me neither, it's rather complicated to follow lambda inner workings.
I see... then a get_pointer overload won't work either, since you can't return a raw pointer from it, and shared_ptr doesn't define operator->*. If you can't cache the shared_ptr locally in aux, the only remaining option is two nested binds.
I'm almost giving up. To sum up what we've got so far, I've written this code // To mimic c++0x auto type (with help of g++'s typeof) #define auto(var, def) typeof(def) var = def struct aux { aux() : b(1) {} int a() const { return 5; } int b; }; int main() { aux a; // This compiles and executes as expected, we're dealing with a pointer to an attribute. boost::function<int(const aux &)> fa = &_1->*&aux::b; int ia = fa(a); cout << ia << endl; // This works, but it's not the way we want, we're dealing with a pointer to a member function. auto(fm1, &_1->*&aux::a); int im1 = fm1(a)(); cout << im1 << endl; // This 'should' work, but doesn't compile. auto(fm2, &protect(_1)->*&aux::a); int im2 = fm2()(a); cout << im2 << endl; return 0; } I think that protect could be used to swap the order of functor instantiations, but it doesn't work. I hope Jaakko Järvi drops by and gives some advice. Thank you very much for your help, Rodolfo Lima.

On Nov 28, 2006, at 5:49 PM, Peter Dimov wrote:
Rodolfo Lima wrote:
function<int(const aux &)> f = (&_1->*&aux::a)();
This doesn't work because you are evaluating the functor without arguments, whereas it requires one.
You are right, it doesn't work; lambda's operator->* seems a pretty odd beast. Interesting that nobody has discovered its quirks so far. FWIW, the syntax above is how it should work in order to be usable. Lambda currently implements
aux x;
(&_1->*&aux::a)( x )();
instead of
(&_1->*&aux::a)()( x );
The current functionality doesn't make much sense to me; if you had x at the time the lambda expression is constructed, you could have used it directly and skip the _1 business.
The reasoning is (or was :) that using a placeholder in an expression does nothing more than delays the evaluation of that expression. So (&_1->*&aux::a)( x ) should have the same semantics as &x->*&aux::a This is how all other operators (+, -, ...) work in Lambda. In the case of ->* this seems in deed confusing, and potentially a less strict interpretation of this principle might be more useful. Cheers, Jaakko
participants (4)
-
Jaakko Järvi
-
Peter Dimov
-
Rodolfo Lima
-
rodolfo@rodsoft.org