1

There is:

template<typename T>
bool any(::Ref<Iterator<T> > i, boost::function<bool(T)> pred) {
    // ...
}

And:

template<typename T> struct Ref {
     // ...
};

template<typename T> struct Iterator {
     // ...
};

Then I have this call (which errors):

int forworm = 42;
bool x = any<CWorm*>(worms(), (_1 ->* &CWorm::getID) == forworm)

And worms() returns a Ref<Iterator<CWorm*> Ref> and there is int CWorm::getID(); (which is a member function).

This fails with a very lengthy error about invalid operands to binary expression. Part of it:

/usr/local/include/boost/lambda/detail/operator_lambda_func_base.hpp:222:1:{222:1-222:63}{222:1-222:63}: error: invalid operands to binary expression ('typename lambda_functor_base >, tuple >, int (CWorm::*const)() const, null_type, null_type, null_type, null_type, null_type, null_type, null_type, null_type> >::sig >::type' (aka 'member_pointer_caller') and 'int') [3]

Why?

How can I fix it?

If I do it somewhat more verbose, i.e. not via lambdas but I declare another function manually and use boost::bind, it works. I.e. like this:

static bool _wormIdEqual(CWorm* w, int wormId) {
    return w->getID() == wormId;
}

any<CWorm*>(worms(), boost::bind(_wormIdEqual, _1, forworm)))
Albert
  • 65,406
  • 61
  • 242
  • 386
  • Try `boost::bind(&CWorm::getID, _1);`. – Naveen Jan 11 '12 at 04:17
  • @Naveen: I don't really know how to use that in combination with `==`. Also, isn't this possible to do with `boost::lambda`? – Albert Jan 11 '12 at 04:22
  • Note that the `operator->*` is essentially an "incomplete function call", and canonically returns a function object which must be called afterwards. See [this answer of mine](http://stackoverflow.com/a/5587323/500104) for more information. @Aaron's answer may look like the same, but the returned lambda from `boost::lambda::bind` will properly propagate the arguments and do The Right Thing™. – Xeo Jan 11 '12 at 05:08

2 Answers2

2

You should be able to do this:

#include <boost/lambda/bind.hpp>

using boost::lambda::bind;
bool x = any<CWorm*>(worms(), bind(&CWorm::getID, _1) == forworm);

The boost::lambda::bind(&CWorm::getID, _1) behaves just as you hoped (_1 ->* &CWorm::getID) would, and can (lazily) compare for equality against forworm. So it's still very much a lambda function.

Xeo
  • 129,499
  • 52
  • 291
  • 397
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • Edited to make it clearer that you mean the `boost::lambda` version of `bind`. – Xeo Jan 11 '12 at 05:09
  • Also, you can theoretically throw away the `boost::lambda` stuff, as it's actually superseded by `boost::bind`, which in turn is again superseded by `boost::phoenix::bind`. So you could use `boost::phoenix::bind` together with its placeholders. I don't know if this would be of any benefit here, though. – Xeo Jan 11 '12 at 05:16
  • And all of that is superseded by C++11's `[]` lambdas? :-) – Aaron McDaid Jan 11 '12 at 14:29
  • 1
    Most of the time. Sometimes, Boost lambdas are just *way* more concise, especially since they're polymorphic. – Xeo Jan 11 '12 at 14:32
  • This SO question, ["What is the difference between boost::bind and boost::lambda::bind?"](http://stackoverflow.com/questions/5202974/what-is-the-difference-between-boostbind-and-boostlambdabind) , and this [Boost page](http://www.boost.org/doc/libs/1_46_0/doc/html/lambda/s08.html#id2143701) , explain the difference nicely. That polymorphism is cool, @Xeo; maybe I should start using boost::bind more actively. I thought I would be able to ignore it once C++11 came along :-) – Aaron McDaid Jan 11 '12 at 16:23
  • I'm curios, why does `(_1 ->* &CWorm::getID)` not work? I thought it would just be equivalent to the `bind`-version. (And I prefer the syntax.) How is it different? – Albert Jan 13 '12 at 01:09
  • 1
    @Albert, To call a member function, you need an object, you need to know which method you want to call, *and* you need to know what parameters to pass to the method. `a->foo(3)` would become something like `(a ->* foo_ptr)(3)`. If you just do `a ->* foo_ptr`, then this is sort of 'equivalent' to `a->foo`. But you don't want `a->foo`, you want `a->foo()`. i.e. you want the method to be actually called. Bind seems to do the right thing here: `bind(&CWorm::getID, _1)` will call it with no parameters. If `getID` took parameters, you could do `bind(&CWorm::getID, _1, "param_1", blue, 3)` – Aaron McDaid Jan 13 '12 at 01:14
  • @Albert, in short, `(_1 ->* &CWorm::getID)` is like `_1->getID`, whereas you want `_1->getID()`. – Aaron McDaid Jan 13 '12 at 01:15
  • Ah, so `(_1 ->* &CWorm::getID)() == forworm` would have worked? – Albert Jan 13 '12 at 01:29
  • No. I've just tried a few things like that, without success. (I've never really used Boost's lambdas, so take this with a pinch of salt.) Lambdas require that the folks at Boost provide overrides for every operator. They didn't provide one for `->*`, as far as I can see. I think you might be able to roll your own, though. – Aaron McDaid Jan 13 '12 at 02:37
0

Quote from Boost.Lambda documentation:

Lambda expressions containing function calls, control structures, casts etc. require special syntactic constructs. Most importantly, function calls need to be wrapped inside a bind function. As an example, consider the lambda expression

You are trying to invoke a function in your code so you must use bind() to actually defer the calling of the function. Moreover, it's also cleaner to delay the variable/constant forworm:

int forworm = 42;
bool x = any<CWorm*>(worms(), bind(&CWorm::getID, _1) == var(forworm));

This answer is an enhancement of @Aaron McDaid's answer, it just got too long for a comment.

Karel Petranek
  • 15,005
  • 4
  • 44
  • 68
  • Why is the delaying of the variable cleaner? I esp. want it to be constant and not be changeable. So, not delaying it actually gives more information to the reader, as in that I don't expect any change of the variable. – Albert Jan 13 '12 at 01:58
  • Then you can stress that by using const_var. It's cleaner because the reader immediately sees that the comparison is evaluated lazily. – Karel Petranek Jan 13 '12 at 18:13