[Boost-users] [bind] How do I....?

28 views
Skip to first unread message

Robert Jones

unread,
Aug 18, 2009, 5:07:14 AM8/18/09
to boost...@lists.boost.org
Use bind to call a free function on a vector of shared_ptrs?

struct A { };
void f(const A&);
std::vector<boost::shared_ptr<A> > v;

for_each(v.begin(), v.end(), boost::bind(f, ???? ) );

what goes where ???? is?

Thanks, Rob.

Neil Groves

unread,
Aug 18, 2009, 5:41:02 AM8/18/09
to boost...@lists.boost.org

Two tactics spring to mind.

One is to use boost::make_indirect_iterator on v.begin() and v.end() and just pass in f instead of the boost::bind(...).

The other is to use RangeEx (shameless plug) thus:

using namespace boost::adaptors;
boost::for_each(v | indirected, f);
 

Thanks, Rob.

Regards,
Neil Groves
 

_______________________________________________
Boost-users mailing list
Boost...@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Björn Karlsson

unread,
Aug 18, 2009, 5:46:52 AM8/18/09
to boost...@lists.boost.org
Hello Rob,

> Subject: [Boost-users] [bind] How do I....?

You have two options if you want to use binders:

1) Use Boost.Bind with nested binds, binding operator* of shared_ptr in the inner bind.

for_each(vec.begin(), vec.end(), boost::bind(&foo, boost::bind(&boost::shared_ptr<A>::operator*, _1)));

2) Use Boost.Lambda's bind() and dereference the placeholder directly in the bind expression.

for_each(vec.begin(), vec.end(), bind(&foo, *_1));


Here's a complete example demonstrating option 2).

#include <vector>
#include <algorithm>
#include "boost/shared_ptr.hpp"

#include "boost/lambda/bind.hpp"
#include "boost/lambda/lambda.hpp"


class A {};

void foo(const A& a) {}

int main(int argc, char** argv)
{
using boost::lambda::bind;
using boost::lambda::_1;

std::vector<boost::shared_ptr<A> > vec;
vec.push_back(boost::shared_ptr<A>(new A()));

for_each(vec.begin(), vec.end(), bind(&foo, *_1));

return 0;
}


Cheers,
Bjorn Karlsson
www.skeletonsoftware.net

Robert Jones

unread,
Aug 18, 2009, 5:53:45 AM8/18/09
to boost...@lists.boost.org
On Tue, Aug 18, 2009 at 10:41 AM, Neil Groves <ne...@grovescomputing.com> wrote:


On Tue, Aug 18, 2009 at 10:07 AM, Robert Jones <robert...@gmail.com> wrote:
Use bind to call a free function on a vector of shared_ptrs?

struct A { };
void f(const A&);
std::vector<boost::shared_ptr<A> > v;

for_each(v.begin(), v.end(), boost::bind(f, ???? ) );

what goes where ???? is?

Two tactics spring to mind.

One is to use boost::make_indirect_iterator on v.begin() and v.end() and just pass in f instead of the boost::bind(...).

Excellent - attack from the opposite direction, I'd not thought of that approach!



The other is to use RangeEx (shameless plug) thus:

using namespace boost::adaptors;
boost::for_each(v | indirected, f);

Ah, if only I could! Doesn't that just demonstrate why RangeEx is so eagerly awaited.

Thanks Neil

- Rob.

Björn Karlsson

unread,
Aug 18, 2009, 6:01:47 AM8/18/09
to boost...@lists.boost.org
Hello Neil,

> Two tactics spring to mind.
>
> One is to use boost::make_indirect_iterator on v.begin() and v.end()
> and just pass in f instead of the boost::bind(...).

Yes, this makes for quite readable code:

for_each(make_indirect_iterator(vec.begin()), make_indirect_iterator(vec.end()), &foo);


> The other is to use RangeEx (shameless plug) thus:
>
> using namespace boost::adaptors;
> boost::for_each(v | indirected, f);
>

Creative! A good example of why it helps to have many power tools!

Cheers,
Bjorn Karlsson
www.skeletonsoftware.net

Robert Jones

unread,
Aug 18, 2009, 5:58:27 AM8/18/09
to boost...@lists.boost.org
2009/8/18 Björn Karlsson <Bjorn.K...@readsoft.com>

Hello Rob,

> Subject: [Boost-users] [bind] How do I....?
>
> Use bind to call a free function on a vector of shared_ptrs?
>
> struct A { };
> void f(const A&);
> std::vector<boost::shared_ptr<A> > v;
>
> for_each(v.begin(), v.end(), boost::bind(f, ???? ) );
>
> what goes where ???? is?
>

You have two options if you want to use binders:

1) Use Boost.Bind with nested binds, binding operator* of shared_ptr in the inner bind.

 for_each(vec.begin(), vec.end(), boost::bind(&foo, boost::bind(&boost::shared_ptr<A>::operator*, _1)));

This was about the best I could think of too, and is, I think, what I'll do.



2) Use Boost.Lambda's bind() and dereference the placeholder directly in the bind expression.

 for_each(vec.begin(), vec.end(), bind(&foo, *_1));

Much as I like Lambda for virgin code, in my work code base there's a very visible inclusion
of Boost.Bind, with placeholders in the global namespace. I've concluded that the pain of clashing
placeholders just isn't worth it, so I steer clear of Lambda now.

Thanks Bjorn.

 - Rob.

Michael Caisse

unread,
Aug 18, 2009, 1:10:25 PM8/18/09
to boost...@lists.boost.org
Robert Jones wrote:
> 2009/8/18 Björn Karlsson <Bjorn.K...@readsoft.com
> <mailto:Bjorn.K...@readsoft.com>>

>
>
>
> 2) Use Boost.Lambda's bind() and dereference the placeholder
> directly in the bind expression.
>
> for_each(vec.begin(), vec.end(), bind(&foo, *_1));
>
>
> Much as I like Lambda for virgin code, in my work code base there's a
> very visible inclusion
> of Boost.Bind, with placeholders in the global namespace. I've
> concluded that the pain of clashing
> placeholders just isn't worth it, so I steer clear of Lambda now.
>
> Thanks Bjorn.
>
> - Rob.

Rob -

Let me suggest Boost.Phoenix. Phoenix is an amazingly powerful library that will
handle all of your bind and lambda needs. You also wont suffer from the plagued
global namespace fiasco by mixing Boost.Bind and Boost.Lambda.

Your example with Phoenix:


#include <vector>
#include <algorithm>
#include <boost/shared_ptr.hpp>

#include <boost/spirit/home/phoenix/core.hpp>
#include <boost/spirit/home/phoenix/operator.hpp>
#include <boost/spirit/home/phoenix/bind/bind_function.hpp>

struct A {};

void foo( const A& ) {}

int main()
{
using namespace boost::phoenix;
using namespace boost::phoenix::arg_names;

std::vector< boost::shared_ptr< A > > vec;
vec.push_back( boost::shared_ptr< A >( new A ) );

std::for_each( vec.begin(), vec.end(),
bind( &foo, *arg1 ) );
return 0;
}


I hope this helps out.

Best Regards -
Michael


--

----------------------------------
Michael Caisse
Object Modeling Designs
www.objectmodelingdesigns.com

OvermindDL1

unread,
Aug 18, 2009, 2:13:01 PM8/18/09
to boost...@lists.boost.org

This is another vote for Boost.Phoenix2, its bind replaces all
possible uses I have ever seen of Boost.Bind or Boost.Lambda::bind and
in an easier way.

Robert Jones

unread,
Aug 18, 2009, 3:58:23 PM8/18/09
to boost...@lists.boost.org
On Tue, Aug 18, 2009 at 6:10 PM, Michael Caisse <bo...@objectmodelingdesigns.com> wrote:
Robert Jones wrote:
2009/8/18 Björn Karlsson <Bjorn.K...@readsoft.com <mailto:Bjorn.K...@readsoft.com>>




   2) Use Boost.Lambda's bind() and dereference the placeholder
   directly in the bind expression.

    for_each(vec.begin(), vec.end(), bind(&foo, *_1));

Much as I like Lambda for virgin code, in my work code base there's a very visible inclusion
of Boost.Bind, with placeholders in the global namespace. I've concluded that the pain of clashing
placeholders just isn't worth it, so I steer clear of Lambda now.

Thanks Bjorn.

 - Rob.

Rob -

Let me suggest Boost.Phoenix. Phoenix is an amazingly powerful library that will
handle all of your bind and lambda needs. You also wont suffer from the plagued
global namespace fiasco by mixing Boost.Bind and Boost.Lambda.

Ah, yes, Phoenix......

I'm never sure of the status of Phoenix - it's not listed as a first class library in
the documentation, but buried inside the Spirit docs, and I understand that's
about to change. So will all the #include paths change, or indeed some aspects
of the functionality?

Thanks Micheal

- Rob.

OvermindDL1

unread,
Aug 19, 2009, 12:11:25 AM8/19/09
to boost...@lists.boost.org

It should not I would think. Phoenix2 (phoenix in spirit, the old
phoenix is phoenix1, ignore it) is heavily used by the very latest
Spirit2.1 codebase, and spirit tends to always include forwarding
headers as things move around anyway.

Michael Caisse

unread,
Aug 19, 2009, 12:18:00 AM8/19/09
to boost...@lists.boost.org
Robert Jones wrote:
> On Tue, Aug 18, 2009 at 6:10 PM, Michael Caisse
> <bo...@objectmodelingdesigns.com
> <mailto:bo...@objectmodelingdesigns.com>> wrote:
>
>
> Let me suggest Boost.Phoenix. Phoenix is an amazingly powerful
> library that will
> handle all of your bind and lambda needs. You also wont suffer
> from the plagued
> global namespace fiasco by mixing Boost.Bind and Boost.Lambda.
>
>
> Ah, yes, Phoenix......
>
> I'm never sure of the status of Phoenix - it's not listed as a first
> class library in
> the documentation, but buried inside the Spirit docs, and I understand
> that's
> about to change. So will all the #include paths change, or indeed some
> aspects
> of the functionality?
>
> Thanks Micheal
>
> - Rob.
Phoenix is an integral part of Spirit 2.1. While it is a "detail"
of sorts you will notice in the libs/spirit directory that Phoenix
has first class treatment. I suspect the best answers to your
questions are in Hartmut's summary of the Phoenix review:

http://lists.boost.org/boost-announce/2008/10/0205.php

Others may have better insider knowledge. I can attest to the
quality of the library and docs as well as the stability. I started
using the library because of Spirit 2.1; however, I now use it
for all of my lambda/bind needs.

Reply all
Reply to author
Forward
0 new messages