GxL Dev
GxL Dev

Reputation: 23

phoenix lambda and argument dereferencing

Can somebody show me how to implement an equivalent of the following using boost::phoenix lambda? I know I could implement it in many other ways but I'm trying to learn the Phoenix lambda expressions and so far all my attempts in this example failed.

What I want to do is to use the std::remove_if to iterate through my set of weak_ptrs and remove the expired ones.

So the code would look something like:

typedef std::set<weak_ptr<Xyz>> XyzWptrSetType;
...
XyzWptrSetType   xyzWptrSet;
...
XyzWptrSetType::iterator it =
    std::remove_if(xyzWptrSet.begin(), xyzWptrSet.end(),
                   (boost::phoenix::arg_names::_1->expied()));  
// the lambda part DOESN'T compile in previous line
std::erase(it, xyzWptrSet.end());

Most of the lambda examples I've found are very simplistic and do not deal with calling a member function on a lambda argument object especially when there is more than one level of indirection. I.e. the _1 is expected to represent the set's iterator which by dereferencing with "->" returns value_type (being weak_ptr), on which I want to call expired. But since _1 is in fact not dirrectly an iterator but rather an "phoenix::actor", my dereferencing doesn't compile.

Thanks for all the creative inputs in advance.

Gabe

Upvotes: 2

Views: 710

Answers (2)

Stuart Berg
Stuart Berg

Reputation: 18161

Boost phoenix (and boost lambda) do not support the -> operator. You can use the "pointer to member" operator (->*) as a reasonable alternative.

I find it useful to define the member pointer as a separate variable immediately before the line that uses a lambda expression:

bool (weak_ptr<Xyz>::*expired)()const = &weak_ptr<Xyz>::expired ;
XyzWptrSetType::iterator it =
    std::remove_if(xyzWptrSet.begin(), xyzWptrSet.end(), (&_1->*expired)() );

As others have noted, it is also worth considering bind() for situations like yours.

Upvotes: 2

Nicol Bolas
Nicol Bolas

Reputation: 473467

Boost.Phoenix, and Boost.Lambda before it, excel at certain tasks, but not at others. One of those others that it doesn't really work at is anything to do with directly calling a function by name.

Boost.Phoenix lambdas can be quickly and easily created for overloaded operators. But if you need a function name, then you have to use ugly syntax:

boost::phoenix::bind(&boost::weak_ptr::expired, boost::phoenix::arg_names::_1)

That is what your lambda looks like. You can use some using directives to clip off namespaces, but that's ultimately what it's going to look like. It's really no different from using boost::bind at this point:

boost::bind(&boost::weak_ptr::expired, _1)

Boost.Phoenix, and Boost.Lambda before it, are best used for lambda expressions that use overloaded operators, or explicitly-defined Phoenix action objects. If you just have a plain old function or member function, you have to bind it to call it. So you may as well just use boost::bind.

Upvotes: 5

Related Questions