find_if + member function

Hi,

What I'd like to do is iterate over a list of objects, checking the return value of a member function for a particular value.

Some groundwork:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <assert.h>
#include <list>

class SampleObject
{
public:
    typedef unsigned int ObjectID;

    SampleObject( ObjectID id ) : m_ID(id) {}
    ObjectID getID() const { return m_ID; }
private:
    ObjectID m_ID;
};

int main()
{
    std::list<SampleObject*> objList;

    objList.push_back(new SampleObject(0));
    objList.push_back(new SampleObject(1));
    objList.push_back(new SampleObject(2));
    objList.push_back(new SampleObject(3));

    std::list<SampleObject*>::iterator iter;
    SampleObject::ObjectID id;

    ...

    return 0;
}


This is simple enough using a for loop:
1
2
3
    id = 0;
    for( iter = objList.begin(); iter != objList.end() && (*iter)->getID() != id; iter++);
    assert( iter != objList.end() && (*iter)->getID() == id );

But, what I'd really like to use is std::find_if (maybe just out of curiosity more than anything else). I've come up with two ways to do this, neither optimal in my opinion.

First, I wrote my own templates to accomplish it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <typename Ret, typename Obj>
class mem_fun_equal_t
{
public:
    mem_fun_equal_t(Ret (Obj::*func)(), Ret val) : m_Func(func), m_Val(val) {}
    bool operator()(Obj* object) { return (object->*m_Func)() == m_Val; }
private:
    Ret (Obj::*m_Func)();
    Ret m_Val;
};

template <typename Ret, typename Obj>
mem_fun_equal_t<Ret, Obj> mem_fun_equal(Ret (Obj::*func)(), Ret val)
{
    return mem_fun_equal_t<Ret, Obj>(func, val);
}

then
1
2
3
    id = 2;
    iter = find_if(objList.begin(), objList.end(), mem_fun_equal(&SampleObject::getID, id));
    assert( iter != objList.end() && (*iter)->getID() == id );

However, I'd really rather find something like this in the STL rather than write it myself.

More poking around in STL documentation resulted in finding mem_fun (I subsequently renamed my solution above as it made more sense). With this, I can do exactly what I want....as long as SampleObject has an additional function:
1
2
3
...
    bool hasID(ObjectID id) const { return m_ID == id; }
...

then
1
2
3
    id = 1;
    iter = find_if(objList.begin(), objList.end(), std::bind2nd(std::mem_fun(&SampleObject::hasID), id) );
    assert( iter != objList.end() && (*iter)->getID() == id );


So, finally on to my question. Is there a) an STL version of my second solution or b) a combination of STL adapters to accomplish my goal without adding an additional function to the class?

My curiosity is piqued, and my brain won't rest until I find a solution to satisfy it. Any ideas?

Thanks,

Keith
You can simplify your first method if you want:
1
2
3
4
5
6
7
8
struct findID: public std::unary_function <SampleObject, bool>{
   typedef SampleObject::ObjectID ObjectID;
   ObjectID id;
   findID( const ObjectID& id ): id( id ) { }//Default constructor to pass the id value
   bool operator () ( const SampleObject *obj ) const{ //overloaded operator to check the condition.
      return id == (*obj).getID();
   }
};


And the call to the find_if will be:
 
find_if( objList.begin(), objList.end(), findID( id ) );


Hope this helps.
You can refer to this older post on something similar:
http://www.cplusplus.com/forum/beginner/2777/

[EDIT]
I don't think that there are STL functions that act on custom class members. And that is because of the unlimited classes that every user can define.
Last edited on
Well, the main reason that I'm not happy with the 2nd and 3rd solution I presented, is that I'd like to limit the changes to within this function. And, defining a class/struct locally and using that with find_if causes compiler errors (understandably).

I was really hoping that there would be some combination of bind2nd, equal_to, mem_fun, or other STL adapters that would result in what I want. I'm just not able to find one.

I don't think that there are STL functions that act on custom class members. And that is because of the unlimited classes that every user can define.
That seems to be exactly what std::mem_fun is for. Adapting custom class member functions for use in other STL adapters.

Thanks for your response, though!

- Keith
I'm sorry I couldn't help.
Probably somebody with more knowledge than me can help you on this.
The STL currently does not provide support for that kind of feature. I thought of four different ways to do it, and the way you did it is probably the simplest.

However, boost::bind and boost::mem_fn will do exactly what you are looking for.
http://www.boost.org/doc/libs/1_35_0/libs/bind/bind.html
http://www.boost.org/doc/libs/1_35_0/libs/bind/mem_fn.html

I don't think it is the least bit unreasonable to expect people to be able to compile code that uses boost libraries (well, the vast majority of them). It might be worth your time to check it out.

Hope this helps.
Here's an example which demonstrates what you need.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <boost/bind.hpp>
#include <vector>

using namespace std;

struct Foo {
   Foo( int y = 0 ) : id( y ) {}
   int GetId() const { return id; }
   int id;
};

int main() {
   vector<Foo> vec;
   for( int x = 0; x < 20; ++x )
       vec.push_back( Foo( x ) );

   if( find_if( vec.begin(), vec.end(), boost::bind( &Foo::GetId, _1 ) == 10 ) != vec.end() )
       cout << "I found it." << endl;
}


Thanks for your responses!

Nesting bind is exactly what I was looking for, but I am working on an embedded system where the boost libraries are not available. But, since it is a boost addition, it does tell me that it cannot (reasonably) be done with the standard STL. That will satisfy my curiosity.

However, unless I'm missing something, I don't think your example would work. The == would compare a boost::bind object with an integer and pass the boolean result to find_if. I think std::equal_to would need to be used in some fashion (thus, making use of the nesting feature of boost::bind). Something like:
1
2
3
...
find_if( vec.begin(), vec.end(), boost::bind( std::equal_to<int>(), boost::bind(std::mem_fun(&Foo::GetId), _1), 10))
...

or for my example
1
2
3
...
std::find_if( objList.begin(), objList.end(), boost::bind( std::equal_to<SampleObject::ObjectID>(), boost::bind(std::mem_fun(&SampleObject::getId), _1), id))
...

From what I'm reading the std::mem_fun calls aren't strictly necessary, but that action is implied and explicitly performing it seems much cleaner to me. But, I suppose if I were to use in any production code, I'd probably leave it out for brevity.

Again, thanks for getting me to take a look at boost::bind. At first it seemed to offer nothing new over std::bind2nd or std::bind1st for my situation. But once I saw the special nesting characteristics, it solved the problem I was running into with the vanilla STL adapters.
You could always cannabalize just the header(s) you need from the boost librari(es) and include it(them) as part of the project.

Anyway, good luck!
Actually, I had to compile and run the example before I posted it so I'm pretty
sure it works. I tried it with both == 10 and == 30, and it found 10 but not 30.

The reason it works is because boost::bind( &Foo::GetId, _1 ) == 10
is a lambda expression and evaluation of it gets deferred until the
encapsulated function is called. boost::function does not provide a
comparison function (operator==). The Magic of Templates and Boost!

Though this means it will be impractical to borrow the boost headers; you'll
need a lot.
Topic archived. No new replies allowed.