36

I have a vector of that looks like the following:

class Foo
{
    //whatever
};

class MyClass
{
    int myInt;
    vector<Foo> foo_v;
};

And let's say, in the main:

int main (void)
{
    vector<MyClass> myClass_v;
}

I want to find a object in myClass_v that has myInt == bar. I don't care about foo_v. I thought of using the std::find_if function:

std::find_if(myClass_v.begin(),myClass_v.end(),condition);

with

bool MyClass::condition(MyClass mc)
{
    if(mc.myInt==5)
        return true;
    else
        return false;
}

However the compiler says that condition() is missing arguments. Could you tell me what am I doing wrong? I thought that std::find_if would call condition(*First), with First being a pointer to a myClass object.

Or is there another good way to do the same thing?

Azeem
  • 11,148
  • 4
  • 27
  • 40
gramm
  • 18,786
  • 7
  • 27
  • 27

4 Answers4

58

That's not how predicates work. You have to supply either a free function bool Comparator(const MyClass & m) { ... }, or build a function object, a class that overloads operator():

struct MyClassComp
{
  explicit MyClassComp(int i) n(i) { }
  inline bool operator()(const MyClass & m) const { return m.myInt == n; }
private:
  int n;
};

std::find_if(v.begin(), v.end(), MyClassComp(5));

In C++0x:

std::find_if(v.begin(), v.end(),
             [](const MyClass & m) -> bool { return m.myInt == 5; });

This captureless lambda is in fact equivalent to a free function. Here is a capturing version that mimics the predicate object:

const int n = find_me();
std::find_if(v.begin(), v.end(),
             [n](const MyClass & m) -> bool { return m.myInt == n; });
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    "Predicate: This can either be a pointer to a function or an object whose class overloads operator()." What's wrong with a function pointer? – orlp Jul 13 '11 at 12:50
  • 3
    Nothing, but if you want to make the comparison value modifiable (my `n`), you need to store it somewhere, so a predicate object is the natural way to hold this extra information. If you only have one globally fixed selection rule, by all means use a free function `bool(const MyClass & m) { ... }`. – Kerrek SB Jul 13 '11 at 12:52
  • 2
    Oh OK, I just found `That's not how predicates work. You have to build a function object.` misleading. – orlp Jul 13 '11 at 12:52
  • 1
    Because you were passing an object to the algorithm, so I figured you're trying to build a predicate! :-) I'll update the answer, though! – Kerrek SB Jul 13 '11 at 12:53
  • Woops, sorry -- as a bonus, I'm adding capturing lambdas. – Kerrek SB Jul 13 '11 at 13:05
  • OP here, thanks a lot :) I'm wondering though, why isn't it possible to use a pointer to function if the function is defined in a class? – gramm Jul 13 '11 at 13:26
  • @Gramm: pointers-to-member and pointers-to-member-function are **not** function pointers. They're very different, incomparable type. Search on SO, you'll find thousands of questions regarding that. – Kerrek SB Jul 13 '11 at 13:27
3
struct condition {
  bool operator()(const MyClass& mc) {
    return mc.myInt == 5;
  }
}
Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
2

You can do it with a functor or a regular function that is not part of MyClass, or with a static function inside MyClass - here's an example with non-member function (basically just removing the MyClass:: part of the condition definition):

#include <algorithm>
#include <vector>

using namespace std;

class Foo
{
  //whatever
};

class MyClass
{
  public:
  int myInt;
  vector<Foo> foo_v;
};

bool condition(MyClass mc)
{
  if(mc.myInt==5)
    return true;
  else
    return false;
}


int main (void)
{
  vector<MyClass> myClass_v;
  std::find_if(myClass_v.begin(),myClass_v.end(),condition);
}
naumcho
  • 18,671
  • 14
  • 48
  • 59
1

Besides what Kerrek SB wrote, you can also use the member function as a predicate.

Define it as bool MyClass::condition() { return mc.myInt==5; } - parameter is unnecessary since it already takes object as implicit parameter.

When using it, wrap &MyClass::condition (pointer to a member function) in std::mem_fcn from functional header.

std::find_if(myClass_v.begin(), myClass_v.end(), std::mem_fcn(&MyClass::condition));


A more verbose way to do it, is to use std::function or std::bind. Replace:

    std::mem_fcn(&MyClass::condition)

with

    std::function<bool (MyClass &)>(&MyClass::condition)    , or
    std::bind(&MyClass::condition, std::placeholders::_1).



If MyClass_v has been declared as std::vector<MyClass *> myClass_v;,

std::function<bool (MyClass &)>(&MyClass::condition) should be altered to: std::function<bool (MyClass *)>(&MyClass::condition). For std::mem_fn and std::bind - no changes are needed.


Code:

#include <vector>
#include <functional>
#include <algorithm>
#include <iostream>

class Foo{};

struct MyClass
{
    int myInt;
    std::vector<Foo> foo_v;
    bool condition(){ return myInt==5; }
};

int main (void)
{
    std::vector<MyClass> myClass_v{ {1,{}}, {3,{}}, {5,{}}, {6,{}} };
    std::cout << std::find_if(myClass_v.begin(), myClass_v.end(), std::mem_fn(&MyClass::condition))->myInt << std::endl;
    return 0;
}
MKPS
  • 175
  • 8