remove_if and member function pointers

J

Jon Rea

Hello all,

Sorry if this is long, but I wanted to be specific...

Can anyone shed any light on the following errors in the context of the
following example code:

cullMethod1(); // compiles, but not what we want - we cant access
m_Exclustions

cullMethod2(); // fine but long-winded and causes many array re-allocations

cullMethod3(); // doen't compile!

i.e. How do you pass a member function to std functions.

Many thanks,
Jon Rea


////////////////////////////////////////////////////
// Begin example code ..

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

using namespace std;

class Bond
{
public:
Bond( int _i, int _j )
{
i = _i;
j = _j;
}
Bond()
{
i = rand();
j = rand();
}
int i;
int j;
};

class MyBase
{
public:
virtual void Setup()
{
int bigNumber = 10000;
for( int i = 0; i < bigNumber; i++ )
{
m_Bonds.push_back( Bond() ); // add lots of random "bonds"
}
}
protected:
std::vector<Bond> m_Bonds;
};

bool mySpecialSelectionFunction( Bond& _b )
{
return _b.i == 47;
}

class MyDerived : public MyBase
{
public:
virtual void Setup()
{
MyBase::Setup();

m_Exclustions.push_back(Bond(43,21));
m_Exclustions.push_back(Bond(12,14));
m_Exclustions.push_back(Bond(1,41));

// Remove all instances of the definitions in m_Exclustions from the
base class list.

// Call ONE of these in real code:
cullMethod1(); // compiles, but not what we want - we cant access
m_Exclustions
cullMethod2(); // fine but long-whinded and causes many array
re-allocations
cullMethod3(); // doen't compile!
}

bool Matches( Bond& bond )
{
for( size_t k = 0; k < m_Exclustions.size(); k++ )
{
if( ( bond.i == m_Exclustions[k].i && bond.j == m_Exclustions[k].j ) ||
( bond.j == m_Exclustions[k].i && bond.i == m_Exclustions[k].j ) )
{
return true;
}
}
return false;
}

void cullMethod1()
{
m_Bonds.erase( remove_if( m_Bonds.begin(), m_Bonds.end(),
mySpecialSelectionFunction ), m_Bonds.end() );
}

void cullMethod2()
{
for( size_t i = 0; i < m_Bonds.size(); /*blank*/ )
{
if( Matches( m_Bonds ) )
{
m_Bonds.erase(m_Bonds.begin()+i);
}
else
{
i++;
}
}
}

void cullMethod3()
{
// Illegal operand on bound member function expression ...
//m_Bonds.erase( remove_if( m_Bonds.begin(), m_Bonds.end(), &Matches
), m_Bonds.end() );

// Term does not evaluare to a function taking 1 arguments ...
//m_Bonds.erase( remove_if( m_Bonds.begin(), m_Bonds.end(),
&MyDerived::Matches ), m_Bonds.end() );

// Term does not evaluare to a function taking 1 arguments ...
//m_Bonds.erase( remove_if( m_Bonds.begin(), m_Bonds.end(),
std::mem_fun_ref(&MyDerived::Matches) ), m_Bonds.end() );
}

protected:
std::vector<Bond> m_Exclustions;
};

int _tmain(int argc, _TCHAR* argv[])
{
MyDerived bob;
bob.Setup();
return 0;
}
 
D

Daniel T.

Jon Rea <[email protected]> said:
Hello all,

Sorry if this is long, but I wanted to be specific...

Can anyone shed any light on the following errors in the context of the
following example code:

cullMethod1(); // compiles, but not what we want - we cant access
m_Exclustions

cullMethod2(); // fine but long-winded and causes many array re-allocations

cullMethod3(); // doen't compile!

i.e. How do you pass a member function to std functions.

First change the signature for Matches:

bool Matches(Bond bond) const
{
...
}

Then you can:

void cullMethod1()
{
m_Bonds.erase(remove_if(m_Bonds.begin(), m_Bonds.end(),
bind1st(mem_fun(&MyDerived::Matches), this)), m_Bonds.end());
}
 
J

Jon Rea

Daniel said:
First change the signature for Matches:

bool Matches(Bond bond) const
{
...
}

Then you can:

void cullMethod1()
{
m_Bonds.erase(remove_if(m_Bonds.begin(), m_Bonds.end(),
bind1st(mem_fun(&MyDerived::Matches), this)), m_Bonds.end());
}

Thanks for the reply. Thats better!

What though if I had to use:
bool Matches(BIG_Bond& bond) const;
because copying a 'BIG_Bond' is an expensive operation.

Cheers,
Jon
 
D

Daniel T.

Thanks for the reply. Thats better!

What though if I had to use:
bool Matches(BIG_Bond& bond) const;
because copying a 'BIG_Bond' is an expensive operation.

Test first. I would not be surprised to find that the compiler optimized
the copy away if the Matches function doesn't modify the parameter in
any way.

However, if you absolutely *had* to use a const& the you can always
create your own selector and then use:

m_Bonds.erase(remove_if(m_Bonds.begin(), m_Bonds.end(),
selector(&MyDerived::Matches, this)), m_Bonds.end());

Before I show you what "selector" looks like, you may be interested in
how I developed it. I put the above code in as the interface I wished,
and then fixed the compile errors until I had something that ran. After
than, I substituted templated tyeps. QED

template < typename Ret, typename Tp, typename Arg >
struct selector_t : unary_function< Arg, Ret >
{
Ret (Tp::*mfn)(Arg) const;
const Tp* obj;

selector_t(Ret(Tp::*x)(Arg) const, const Tp* y): mfn(x), obj(y) { }

Ret operator()(Arg x) const {
return (obj->*mfn)(x);
}
};

template < typename Ret, typename Tp, typename Arg >
selector_t< Ret, Tp, Arg > selector(Ret(Tp::*x)(Arg) const, Tp* y) {
return selector_t< Ret, Tp, Arg >(x, y);
}

And yes, I double checked. Arg in the above template is a "const Bond&"
and not a "Bond".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,692
Latest member
JenniferTi

Latest Threads

Top