views:

195

answers:

1

I have a function of the form:

void DoSomething(const boost::function<bool ()>& condition, other stuff);

This function does some work and returns only when the condition is true. The condition has been expressed as a functor argument because I want to supply different conditions at different call sites.

Now, this is fairly straightforward to use directly, but it requires declaring lots of little throwaway functions or functor objects, which I'd like to avoid if possible. I've been looking at Boost's lambda library for possible ways to do away with these, but I think I'm missing something fundamental; I just can't get it to do what I want.

One case that's stumped me at the moment: I have a std::vector collection called data; the condition that I'm after is when the size() of that collection reaches a certain threshold. Essentially, then, I want my condition functor to return true when data.size() >= threshold and false otherwise. But I've been having trouble expressing that in lambda syntax.

The best that I've been able to come up with thus far (which at least compiles, though it doesn't work) is this:

boost::function<bool (size_t)> ge = boost::bind(std::greater_equal<size_t>(),
                                                _1, threshold);
boost::function<size_t ()> size = boost::bind(&std::vector<std::string>::size,
                                              data);
DoSomething(boost::lambda::bind(ge, boost::lambda::bind(size)), other stuff);

On entry to DoSomething, the size is 0 -- and even though the size increases during the course of running, the calls to condition() always seem to get a size of 0. Tracing it through (which is a bit tricky through Boost's internals), while it does appear to be calling greater_equal each time condition() is evaluated, it doesn't appear to be calling size().

So what fundamental thing have I completely messed up? Is there a simpler way of expressing this sort of thing (while still keeping the code as inline as possible)?

I'd ideally like to get it as close as possible to the C# equivalent code fluency:

DoSomething(delegate() { return data.size() >= threshold; }, other stuff);
DoSomething(() => (data.size() >= threshold), other stuff);
+5  A: 

The problem is, that the lambda function stores a copy of the data vector, not a reference. So size() is called on the copy, not the original object that you are modifying. This can be solved by wrapping data with boost::ref, which stores a reference instead:

boost::function<size_t ()> size = boost::bind(&std::vector<std::string>::size,
                                              boost::ref(data));

You can also use the normal >= operator instead of std::greater_equal<> in the definition of your lambda function and combine it all together:

boost::function<bool ()> cond =
    (boost::bind(&std::vector<std::string>::size, boost::ref(data))
        >= threshold);

DoSomething(cond, other stuff);
sth
Thanks, that worked. Though it's surprising to me that you can apply >= like that to a bound function -- especially since it's not even the lambda bind! :)
Miral
The >= is overloaded for the function object, but maybe boost::lambda::bind would be a better choice anyway...
sth