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

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
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
' to 'int' in return
Try
function

function
f = (&_1->*&aux::a)();
This doesn't work because you are evaluating the functor without arguments, whereas it requires one.
function
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
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

Rodolfo Lima wrote:
function
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
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
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
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
f = &aux::a; works through it, too.
What if aux::a has a parameter? I'd like to do:
function

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

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

On Nov 28, 2006, at 5:49 PM, Peter Dimov wrote:
Rodolfo Lima wrote:
function
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