Using boost::lamba with a vector of shared_ptr's
Hello all.
I am having trouble with the boost lambda library. I am convinced that
my troubles come from some little thing I am overlooking, but for the
life of me I can't seem to find the problem. I have been looking at it
for the entire afternoon with no solution in sight.
I have included some sample code below showing the basic idea of what I
am trying to accomplish. Can anyone provide me with a working solution?
The summary is:
- I have a vector of shared_ptr's to a class A
- That class has a method that returns a value I would like to test for
in a find_if call
============================================================
namespace bl = boost::lambda
class A
{
int getInt();
};
class Foo
{
A bar();
}
std::vector
Allen Bierbaum wrote:
Hello all.
I am having trouble with the boost lambda library. I am convinced that my troubles come from some little thing I am overlooking, but for the life of me I can't seem to find the problem. I have been looking at it for the entire afternoon with no solution in sight.
I have included some sample code below showing the basic idea of what I am trying to accomplish. Can anyone provide me with a working solution?
The summary is: - I have a vector of shared_ptr's to a class A - That class has a method that returns a value I would like to test for in a find_if call
[...]
Can anyone tell me how I can call a method from a lamda method iterating over a sequence of shared_ptrs? And then how do I have this method also call another method?
The short answer is that you can't, at least with the current implementation. There are three possible ways to call a member function with Lambda: (bl::_1 ->* &Foo::bar )(foo_ptr); bl::bind(&Foo::bar, *bl::_1)(foo_ptr); bl::bind(&Foo::bar, bl::_1)(foo_ptr); The first alternative doesn't work since shared_ptr does not have operator->*. The second alternative doesn't work since Lambda doesn't support *_1 for shared_ptr. The third alternative doesn't work since it is not supported by Lambda (probably by design), although it is supported by Bind, and may be supported by a future version of Lambda. The Bind equivalent is: boost::bind(&Foo::bar, _1)(foo_ptr); and it does work. Your complete example can be written with Bind as: std::find_if( foos.begin(), foos.end(), boost::bind(std::equal_to<int>(), boost::bind(&A::getInt, boost::bind(&Foo::bar, _1) ), find_int ) ); It is clumsier since the more limited Bind vocabulary forces the use of std::equal_to instead of simply composing an expression using operator==. You need to make A::getInt() const, though. Non-const member functions can be invoked on rvalues, but Bind isn't sophisticated enough to realize that. I suspect that in your real code getInt is const. All that said, you might want to rethink whether you want to use Lambda or Bind in this way here. A helper function would simplify the example considerably: bool has_guid(shared_ptr<Foo> const & p, int guid) { return p->bar().getInt() == guid; } std::find_if( first, last, bind( has_guid, _1, child_guid) ); HTH
On Fri, 21 Nov 2003, Peter Dimov wrote:
Allen Bierbaum wrote:
Hello all.
I am having trouble with the boost lambda library. I am convinced that my troubles come from some little thing I am overlooking, but for the life of me I can't seem to find the problem. I have been looking at it for the entire afternoon with no solution in sight.
I have included some sample code below showing the basic idea of what I am trying to accomplish. Can anyone provide me with a working solution?
The summary is: - I have a vector of shared_ptr's to a class A - That class has a method that returns a value I would like to test for in a find_if call
[...]
Can anyone tell me how I can call a method from a lamda method iterating over a sequence of shared_ptrs? And then how do I have this method also call another method?
The short answer is that you can't, at least with the current implementation.
There are three possible ways to call a member function with Lambda:
(bl::_1 ->* &Foo::bar )(foo_ptr); bl::bind(&Foo::bar, *bl::_1)(foo_ptr); bl::bind(&Foo::bar, bl::_1)(foo_ptr);
The first alternative doesn't work since shared_ptr does not have operator->*.
The second alternative doesn't work since Lambda doesn't support *_1 for shared_ptr.
In particular, Lambda's return type deduction templates are not aware of shared_ptr. The second example can be made to work by telling the library what the return type of calling operator* on a shared_ptr<Foo> is: bl::bind(&Foo::bar, bl::ret<&Foo>(*bl::_1))(foo_ptr);
The third alternative doesn't work since it is not supported by Lambda (probably by design), although it is supported by Bind, and may be supported by a future version of Lambda.
Yup, bind is special cased for shared_ptr's, lambda doesn't know anything about them. Best, Jaakko
Hi, Jaakko Jarvi wrote:
The second alternative doesn't work since Lambda doesn't support *_1 for shared_ptr.
In particular, Lambda's return type deduction templates are not aware of shared_ptr.
They do not need to be aware of shared_ptr. shared_ptr provides ::element_type, for consistency with std::auto_ptr. boost::shared_ptr also has ::reference, although tr1::shared_ptr might not. You just need to look for the individual typedef and not instantiate iterator_traits prematurely.
Yup, bind is special cased for shared_ptr's, ...
No it is not. :-)
Peter Dimov wrote: [...] Oh well, not truly offlist, sorry. ;-)
On Fri, 21 Nov 2003, Peter Dimov wrote:
Hi,
Jaakko Jarvi wrote:
The second alternative doesn't work since Lambda doesn't support *_1 for shared_ptr.
In particular, Lambda's return type deduction templates are not aware of shared_ptr.
They do not need to be aware of shared_ptr. shared_ptr provides ::element_type, for consistency with std::auto_ptr. boost::shared_ptr also has ::reference, although tr1::shared_ptr might not. You just need to look for the individual typedef and not instantiate iterator_traits prematurely.
Ok, thanks. In any case, lambda's return type deduction rules do not cover the convention of ::element_type. Jaakko
"Peter Dimov"
Hi,
Jaakko Jarvi wrote:
The second alternative doesn't work since Lambda doesn't support *_1 for shared_ptr.
In particular, Lambda's return type deduction templates are not aware of shared_ptr.
They do not need to be aware of shared_ptr. shared_ptr provides ::element_type, for consistency with std::auto_ptr. boost::shared_ptr also has ::reference, although tr1::shared_ptr might not. You just need to look for the individual typedef and not instantiate iterator_traits prematurely.
But what if iterator_traits is specialized? The typedef could say the wrong thing. -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
"Peter Dimov"
writes: Hi,
Jaakko Jarvi wrote:
The second alternative doesn't work since Lambda doesn't support *_1 for shared_ptr.
In particular, Lambda's return type deduction templates are not aware of shared_ptr.
They do not need to be aware of shared_ptr. shared_ptr provides ::element_type, for consistency with std::auto_ptr. boost::shared_ptr also has ::reference, although tr1::shared_ptr might not. You just need to look for the individual typedef and not instantiate iterator_traits prematurely.
But what if iterator_traits is specialized? The typedef could say the wrong thing.
Technically yes. We know that 100% reliable return type inference is impossible. In practice we want it to work most of the time, and currently the opposite is true. Of course this would have been mostly academic if the simpler bind(&X::f, _1) syntax worked with Lambda.
participants (4)
-
Allen Bierbaum
-
David Abrahams
-
Jaakko Jarvi
-
Peter Dimov