2

Let's say I have this type:

typedef boost::function<bool (Foo)> filter_function;

And a vector of those "filter functions":

std::vector<filter_function> filters;

If want to call all the filter functions, one by one, and only the the last call returned true.

Inspired by a previous question, I ended up writing:

bool Bar::filterFoo(Foo& foo)
{
  return (std::find_if(filters.begin(), filters.end(), boost::lambda::bind(boost::lambda::_1, foo)) == filters.end());
}

But this is wrong: the return value of the lambda should be negated.

I tried to use std::not1, std::not2 at different places but couldn't find any variation that doesn't end up in a (pretty verbose) compilation error.

What is the correct way to do this ?

Community
  • 1
  • 1
ereOn
  • 53,676
  • 39
  • 161
  • 238

1 Answers1

2

You can simply negate the return value.

bool Bar::filterFoo(Foo& foo)
{
  return (std::find_if(filters.begin(), filters.end(), !boost::lambda::bind(boost::lambda::_1, foo)) == filters.end());
}

or you can use lambda from c++0X

bool Bar::filterFoo(Foo& foo)
{
    return (std::find_if(filters.begin(), filters.end(), [&foo](filter_function& f){
        return !f(foo);
    }
    ) == filters.end());
}

To show a complete example that works at least for VS2010.

#include <iostream>
#include <vector>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/bind.hpp>
#include <boost/lambda/bind.hpp>

using namespace std;

struct Foo{};

typedef boost::function<bool (Foo)> filter_function;
std::vector<filter_function> filters;

static int g_c = 0;
bool MyFunc(Foo /*foo*/)
{
    if(g_c > 1)
        return true;
    g_c++;
    return false;
}
bool filterFoo(Foo& foo)
{
    return (std::find_if(filters.begin(), filters.end(), boost::lambda::bind(boost::lambda::_1, foo)) == filters.end());
}
bool negatefilterFoo(Foo& foo)
{
    return (std::find_if(filters.begin(), filters.end(), !boost::lambda::bind(boost::lambda::_1, foo)) == filters.end());
}

int main() 
{
    Foo f;
    filters.push_back(boost::bind(&MyFunc, _1));
    filters.push_back(boost::bind(&MyFunc, _1));
    filters.push_back(boost::bind(&MyFunc, _1));
    std::cout << filterFoo(f) << std::endl;
    std::cout << negatefilterFoo(f) << std::endl;
    return 0;
}

It returns 0 and 1 on my machine.

mkaes
  • 13,781
  • 10
  • 52
  • 72
  • Thank you for your answer. The `!` operator doesn't seem to be overloaded for `boost::lambda::bind` as I get this compilation error: "no match for 'operator!' in '!boost::lambda::bind(const Arg1&, const Arg2)". And unfortunately, I can't use C++0x. – ereOn Jun 28 '11 at 14:32
  • 1
    I don't think ! will work since the 3rd parameter for find_if() is expecting a functor, and ! requires a bool. But then again, I don't know if C++0x changes this. – void.pointer Jun 28 '11 at 14:35
  • @ereOn: Which compiler are you using and which boost version? – mkaes Jun 28 '11 at 14:57
  • @mkaes: My code must compile on GCC (Windows, UNIX, Linux and Mac OSX) and VS2010. – ereOn Jun 28 '11 at 14:59
  • @ereOn: VS2010 will work. And I have a gcc 3.4.4 in a cygwin env that also accepts the negation of the lambda. But I am using boost 1.46.1. So if you are using an older version try the latest one. – mkaes Jun 28 '11 at 15:08
  • I ended up using `boost::bind` which was more suited to my task. But I took advice from your answer and used `!` to negate it (it worked for `boost::bind`). Both upvoting and accepting this answer as it lead me to the solution. Thank you. – ereOn Jun 28 '11 at 15:24
  • @ereOn: Still could you please let me know which boost version you are using? I am still interested why the negate of the lambda works on my compiler but not on yours. – mkaes Jun 28 '11 at 15:32
  • The weird thing is I'm also using 1.46.1. Are you using `boost::function` or raw function pointers ? – ereOn Jun 28 '11 at 15:35
  • I added a complete example that should compile to my answer. This works fine for me. – mkaes Jun 28 '11 at 15:39
  • 3
    To get `!` to work, you need *lambda.hpp*, not just *bind.hpp*. That's where the operator overloads come from. Without *lambda.hpp*, you're stuck with the built-in operators, which obviously don't work the way you need them to. – Rob Kennedy Jun 28 '11 at 15:49
  • @Rob: Thanks for the hint. That was what I wanted to know. – mkaes Jun 28 '11 at 15:51